home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 June: Reference Library / Dev.CD Jun 95 / Dev.CD Jun 95.toast / Technical Documentation / Inside Macintosh / Sound / Sound
Encoding:
Text File  |  1994-10-25  |  6.6 MB  |  13,088 lines  |  [ONLN/HLX2]

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1. INSIDE MACINTOSH
  2.  
  3. Sound
  4.     Apple Computer, Inc.
  5. © 1994 Apple Computer, Inc.
  6. All rights reserved. 
  7. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, electronic, photocopying, recording, or otherwise, without prior written permission of Apple Computer, Inc. Printed in the United States of America.
  8. No licenses, express or implied, are granted with respect to any of the technology described in this book. Apple retains all intellectual property rights associated with the technology described in this book. This book is intended to assist application developers to develop applications only for Apple Macintosh computers.
  9. Every effort has been made to ensure that the information in this manual is accurate. Apple is not responsible for printing or clerical errors.
  10. Apple Computer, Inc.
  11. 20525 Mariani Avenue
  12. Cupertino, CA 95014
  13. 408-996-1010
  14. Apple, the Apple logo, APDA, HyperCard, LaserWriter, Macintosh, Macintosh Quadra, MPW, and PowerBook are trademarks of Apple Computer, Inc., registered in the United States and other countries.
  15. AppleDesign, AudioVision, Finder, MacinTalk, QuickDraw, and QuickTime are trademarks of Apple Computer, Inc.
  16. Adobe Illustrator, Adobe Photoshop, and PostScript are trademarks of Adobe Systems Incorporated, which may be registered in certain jurisdictions.
  17. Classic® is a registered trademark licensed to Apple Computer, Inc.
  18. FrameMaker is a registered trademark of Frame Technology Corporation.
  19. Helvetica and Palatino are registered trademarks of Linotype Company.
  20. Internet is a trademark of Digital Equipment Corporation.
  21. ITC Zapf Dingbats is a registered trademark of International Typeface Corporation.
  22. NuBus™ is a trademark of Texas Instruments.
  23. Optrotech is a trademark of Orbotech Corporation.
  24. Sony™ is a trademark of Sony Corporation, registered in the U.S. and other countries.
  25. Simultaneously published in the United States and Canada.
  26. LIMITED WARRANTY ON MEDIA AND REPLACEMENT
  27. ALL IMPLIED WARRANTIES ON THIS MANUAL, INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE LIMITED IN DURATION TO NINETY (90) DAYS FROM THE DATE OF THE ORIGINAL RETAIL PURCHASE OF THIS PRODUCT.
  28. Even though Apple has reviewed this manual, APPLE MAKES NO WARRANTY OR REPRESENTATION, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS MANUAL, ITS QUALITY, ACCURACY, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. AS A RESULT, THIS MANUAL IS SOLD “AS IS,” AND YOU, THE PURCHASER, ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND ACCURACY.
  29. IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT OR INACCURACY IN THIS MANUAL, even if advised of the possibility of such damages.
  30. THE WARRANTY AND REMEDIES SET FORTH ABOVE ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer, agent, or employee is authorized to make any modification, extension, or addition to this warranty.
  31. Some states do not allow the exclusion or limitation of implied warranties or liability for incidental or consequential damages, so the above limitation or exclusion may not apply to you. This warranty gives you specific legal rights, and you may also have other rights which vary from state to state.
  32. ISBN 0-201-62272-6
  33. 1 2 3 4 5 6 7 8 9-CRW-9897969594
  34. First Printing, May 1994
  35. The paper used in this book meets the EPA standards for recycled fiber.
  36. Library of Congress Cataloging-in-Publication Data
  37. Inside Macintosh. Sound / [Apple Computer, Inc.]
  38.     p.cm.
  39. Includes index.
  40. ISBN 0-201-62272-6
  41. 1. Macintosh (Computer)2. Computer sound processing.I. Apple 
  42. Computer, Inc.
  43. QA76.8.M3I531994
  44. 006.5--dc20    94-16209
  45. CIP
  46. Contents
  47. Figures, Tables, and Listingsxi
  48. Preface    About This Bookxv
  49.  
  50. Format of a Typical Chapterxvi
  51. Conventions Used in This Bookxvi
  52. Special Fontsxvi
  53. Types of Notesxvii
  54. Assembly-Language Informationxvii
  55. Development Environmentxviii
  56. For More Informationxix
  57. Chapter 1    Introduction to Sound on the Macintosh1-1
  58.  
  59. About Sound on Macintosh Computers1-4
  60. Sound Capabilities1-4
  61. Sound Production1-9
  62. Sound Recording1-15
  63. Sound Resources1-17
  64. Sound Files1-18
  65. Speech Generation1-20
  66. The User Interface for Sound1-23
  67. Using Sound on Macintosh Computers1-24
  68. Producing an Alert Sound1-24
  69. Playing a Sound Resource1-25
  70. Playing a Sound File 1-26
  71. Checking For Sound-Recording Equipment1-27
  72. Recording a Sound Resource1-28
  73. Recording a Sound File1-31
  74. Checking For Speech Capabilities1-31
  75. Generating Speech From a String1-32
  76. Sound Reference1-34
  77. Routines1-34
  78. Playing Sounds1-34
  79. Recording Sounds1-38
  80. Generating and Stopping Speech1-41
  81. Summary of Sound1-44
  82. Pascal Summary1-44
  83. Constants1-44
  84. Routines1-44
  85. C Summary1-45
  86. Constants1-45
  87. Routines1-46
  88. Result Codes1-47
  89. Chapter 2    Sound Manager2-1
  90.  
  91. About the Sound Manager2-6
  92. Sound Data2-7
  93. Square-Wave Data2-7
  94. Wave-Table Data2-8
  95. Sampled-Sound Data2-9
  96. Sound Commands2-11
  97. Sound Channels2-13
  98. Sound Compression and Expansion2-14
  99. Using the Sound Manager2-17
  100. Managing Sound Channels2-19
  101. Allocating Sound Channels2-20
  102. Initializing Sound Channels2-22
  103. Releasing Sound Channels2-24
  104. Manipulating a Sound That Is Playing2-25
  105. Stopping Sound Channels2-28
  106. Pausing and Restarting Sound Channels2-29
  107. Synchronizing Sound Channels2-30
  108. Managing Sound Volumes2-31
  109. Obtaining Sound-Related Information2-32
  110. Obtaining Information About Available Sound Features2-33
  111. Obtaining Version Information2-34
  112. Testing for Multichannel Sound and Play-From-Disk Capabilities2-35
  113. Obtaining Information About a Single Sound Channel2-37
  114. Obtaining Information About All Sound Channels2-39
  115. Determining and Changing the Status of the System Alert Sound2-40
  116. Playing Notes2-41
  117. Installing Voices Into Channels  2-43
  118. Looping a Sound Indefinitely2-45
  119. Playing Sounds Asynchronously 2-46
  120. Using Callback Procedures2-47
  121. Synchronizing Sound With Other Actions2-51
  122. Managing an Asynchronous Play From Disk2-52
  123. Playing Selections2-53
  124. Managing Multiple Sound Channels2-53
  125. Parsing Sound Resources and Sound Files2-56
  126. Obtaining a Pointer to a Sound Header2-57
  127. Playing Sounds Using Low-Level Routines2-61
  128. Finding a Chunk in a Sound File2-62
  129. Compressing and Expanding Sounds2-66
  130. Using Double Buffers2-68
  131. Setting Up Double Buffers2-70
  132. Writing a Doubleback Procedure2-72
  133. Sound Storage Formats2-73
  134. Sound Resources2-74
  135. The Format 1 Sound Resource2-75
  136. The Format 2 Sound Resource 2-80
  137. Sound Files2-81
  138. Chunk Organization and Data Types2-82
  139. The Form Chunk2-83
  140. The Format Version Chunk2-84
  141. The Common Chunk2-85
  142. The Sound Data Chunk2-87
  143. Format of Entire Sound Files2-87
  144. Sound Manager Reference2-89
  145. Constants2-89
  146. Gestalt Selector and Response Bits2-90
  147. Channel Initialization Parameters2-91
  148. Sound Command Numbers2-92
  149. Chunk IDs2-98
  150. Data Structures2-99
  151. Sound Command Records2-99
  152. Audio Selection Records2-100
  153. Sound Channel Status Records2-101
  154. Sound Manager Status Records2-102
  155. Sound Channel Records2-103
  156. Sound Header Records2-104
  157. Extended Sound Header Records2-106
  158. Compressed Sound Header Records2-108
  159. Sound Double Buffer Header Records2-111
  160. Sound Double Buffer Records2-112
  161. Chunk Headers2-113
  162. Form Chunks2-113
  163. Format Version Chunks2-114
  164. Common Chunks2-115
  165. Extended Common Chunks2-115
  166. Sound Data Chunks 2-117
  167. Version Records2-118
  168. Leftover Blocks2-119
  169. State Blocks2-119
  170. Sound Manager Routines2-119
  171. Playing Sound Resources2-120
  172. Playing From Disk2-123
  173. Allocating and Releasing Sound Channels2-127
  174. Sending Commands to a Sound Channel2-130
  175. Obtaining Information2-132
  176. Controlling Volume Levels2-139
  177. Compressing and Expanding Audio Data2-142
  178. Managing Double Buffers2-147
  179. Performing Unsigned Fixed-Point Arithmetic2-148
  180. Linking Modifiers to Sound Channels2-149
  181. Application-Defined Routines2-151
  182. Completion Routines2-151
  183. Callback Procedures 2-152
  184. Doubleback Procedures2-153
  185. Resources2-154
  186. The Sound Resource2-154
  187. Summary of the Sound Manager2-157
  188. Pascal Summary2-157
  189. Constants2-157
  190. Data Types2-161
  191. Sound Manager Routines2-168
  192. Application-Defined Routines2-170
  193. C Summary2-170
  194. Constants2-170
  195. Data Types2-175
  196. Sound Manager Routines2-182
  197. Application-Defined Routines2-184
  198. Assembly-Language Summary2-184
  199. Data Structures2-184
  200. Trap Macros2-188
  201. Result Codes2-188
  202. Chapter 3    Sound Input Manager3-1
  203.  
  204. About the Sound Input Manager3-3
  205. Sound Recording Without the Standard Interface3-4
  206. Interaction With Sound Input Devices3-4
  207. Sound Input Device Drivers3-5
  208. Using the Sound Input Manager3-5
  209. Recording Sounds Directly From a Device3-6
  210. Defining a Sound Input Completion Routine3-9
  211. Defining a Sound Input Interrupt Routine3-10
  212. Getting and Setting Sound Input Device Information3-10
  213. Writing a Sound Input Device Driver3-13
  214. Responding to Status and Control Requests3-13
  215. Responding to Read Requests3-15
  216. Supporting Stereo Recording3-16
  217. Supporting Continuous Recording3-17
  218. Sound Input Manager Reference3-17
  219. Constants3-17
  220. Gestalt Selector and Response Bits3-17
  221. Sound Input Device Information Selectors3-18
  222. Data Structures3-26
  223. Sound Input Parameter Blocks3-26
  224. Sound Input Manager Routines3-27
  225. Recording Sounds3-28
  226. Opening and Closing Sound Input Devices3-31
  227. Recording Sounds Directly From Sound Input Devices3-33
  228. Manipulating Device Settings3-41
  229. Constructing Sound Resource and File Headers3-44
  230. Registering Sound Input Devices3-48
  231. Converting Between Milliseconds and Bytes3-51
  232. Obtaining Information3-53
  233. Application-Defined Routines3-53
  234. Sound Input Completion Routines3-54
  235. Sound Input Interrupt Routines3-55
  236. Summary of the Sound Input Manager3-57
  237. Pascal Summary3-57
  238. Constants3-57
  239. Data Types3-58
  240. Sound Input Manager Routines3-59
  241. Application-Defined Routines3-60
  242. C Summary3-61
  243. Constants3-61
  244. Data Types3-62
  245. Sound Input Manager Routines3-63
  246. Application-Defined Routines3-65
  247. Assembly-Language Summary3-65
  248. Data Structures3-65
  249. Trap Macros3-66
  250. Result Codes3-66
  251. Chapter 4    Speech Manager4-1
  252.  
  253. About the Speech Manager4-4
  254. Voices4-5
  255. Speech Attributes4-6
  256. Speech Channels4-9
  257. Callback Routines4-10
  258. Using the Speech Manager4-11
  259. Checking for Speech Manager Capabilities4-12
  260. Creating, Using, and Disposing of a Speech Channel4-13
  261. Working With Different Voices4-14
  262. Adjusting Speech Attributes4-16
  263. Pausing Speech4-18
  264. Implementing Callback Procedures4-19
  265. Writing Embedded Speech Commands4-23
  266. Embedded Command Delimiters4-23
  267. Syntax of Embedded Speech Commands4-24
  268. Examples of Embedded Speech Commands4-30
  269. Phonemic Representation of Speech4-32
  270. Phonemic Symbols4-33
  271. Prosodic Control Symbols4-34
  272. Including Pronunciation Dictionaries 4-36
  273. Speech Manager Reference4-39
  274. Constants4-39
  275. Speech Information Selectors4-39
  276. Data Structures4-45
  277. Voice Specification Records4-46
  278. Voice Description Records4-47
  279. Voice File Information Records4-48
  280. Speech Status Information Records4-48
  281. Speech Error Information Records4-49
  282. Speech Version Information Records4-50
  283. Phoneme Information Records4-52
  284. Phoneme Descriptor Records4-53
  285. Speech Extension Data Records4-53
  286. Delimiter Information Records4-54
  287. Speech Manager Routines4-54
  288. Starting, Stopping, and Pausing Speech4-55
  289. Obtaining Information About Voices4-63
  290. Managing Speech Channels4-69
  291. Obtaining Information About Speech4-71
  292. Changing Speech Attributes4-73
  293. Converting Text To Phonemes4-79
  294. Installing a Pronunciation Dictionary4-80
  295. Application-Defined Routines4-82
  296. Text-Done Callback Procedure4-82
  297. Speech-Done Callback Procedure4-84
  298. Synchronization Callback Procedure4-85
  299. Error Callback Procedure4-86
  300. Phoneme Callback Procedure4-87
  301. Word Callback Procedure4-88
  302. Resources4-89
  303. The Pronunciation Dictionary Resource4-89
  304. Summary of the Speech Manager4-94
  305. Pascal Summary4-94
  306. Constants4-94
  307. Data Structures4-95
  308. Speech Manager Routines4-98
  309. Application-Defined Routines4-100
  310. C Summary4-100
  311. Constants4-100
  312. Data Types4-102
  313. Speech Manager Routines4-105
  314. Application-Defined Routines4-106
  315. Assembly-Language Information4-107
  316. Data Structures4-107
  317. Trap Macros4-109
  318. Result Codes4-110
  319. Chapter 5    Sound Components5-1
  320.  
  321. About Sound Components5-4
  322. Sound Component Chains5-4
  323. The Apple Mixer5-6
  324. The Data Stream5-7
  325. Writing a Sound Component5-8
  326. Creating a Sound Component5-8
  327. Specifying Sound Component Capabilities5-11
  328. Dispatching to Sound Component-Defined Routines5-12
  329. Registering and Opening a Sound Component5-16
  330. Finding and Changing Component Capabilities5-18
  331. Sound Components Reference5-22
  332. Constants5-22
  333. Sound Component Information Selectors5-22
  334. Audio Data Types5-26
  335. Sound Component Features Flags5-26
  336. Action Flags5-27
  337. Data Format Flags5-28
  338. Data Structures5-29
  339. Sound Component Data Records5-29
  340. Sound Parameter Blocks5-30
  341. Sound Information Lists5-31
  342. Compression Information Records5-32
  343. Sound Manager Utilities5-33
  344. Opening and Closing the Apple Mixer Component5-33
  345. Saving and Restoring Sound Component Preferences5-35
  346. Sound Component-Defined Routines5-36
  347. Managing Sound Components5-37
  348. Creating and Removing Audio Sources5-42
  349. Getting and Setting Sound Component Information5-44
  350. Managing Source Data5-46
  351. Summary of Sound Components5-50
  352. C Summary5-50
  353. Constants5-50
  354. Data Types5-53
  355. Sound Manager Utilities5-54
  356. Sound Component-Defined Routines5-55
  357. Assembly-Language Summary5-56
  358. Data Structures5-56
  359. Chapter 6    Audio Components6-1
  360.  
  361. About Audio Components6-3
  362. Writing an Audio Component6-5
  363. Creating an Audio Component6-5
  364. Dispatching to Audio Component-Defined Routines6-7
  365. Audio Components Reference6-8
  366. Data Structures6-8
  367. Audio Information Records6-9
  368. Audio Component-Defined Routines6-9
  369. Getting and Setting Volumes6-10
  370. Managing the Mute State6-11
  371. Resetting Audio Components6-13
  372. Getting Audio Component Information6-13
  373. Summary of Audio Components6-15
  374. C Summary6-15
  375. Constants6-15
  376. Data Types6-16
  377. Audio Component-Defined Routines6-16
  378. Assembly-Language Summary6-17
  379. Data Structures6-17
  380. GlossaryGL-1
  381.  
  382. IndexIN-1
  383. Figures, Tables, and Listings
  384. Chapter 1    Introduction to Sound on the Macintosh1-1
  385.  
  386. Figure 1-1    Basic sound capabilities on Macintosh computers1-4
  387. Figure 1-2    Enhanced sound capabilities on Macintosh computers1-6
  388. Figure 1-3    High quality sound capabilities on Macintosh computers1-7
  389. Figure 1-4    A sound component chain1-8
  390. Figure 1-5    A sound component chain with a DSP board1-9
  391. Figure 1-6    The Sound Out control panel1-10
  392. Figure 1-7    The relation of the Sound Manager to the audio hardware1-11
  393. Figure 1-8    Bypassing the command queue1-13
  394. Figure 1-9    Mixing multiple channels of sampled sound1-14
  395. Figure 1-10    The Sound In control panel1-15
  396. Figure 1-11    The Alert Sounds control panel1-16
  397. Figure 1-12    The sound recording dialog box1-17
  398. Figure 1-13    The speech generation process1-21
  399. Figure 1-14    The Speech Manager and multiple voices1-21
  400. Figure 1-15    An icon for a Finder sound1-23
  401. Figure 1-16    A sound in the Scrapbook1-24
  402. Table 1-1    AIFF and AIFF-C capabilities1-19
  403. Listing 1-1    Playing a sound resource with SndPlay1-25
  404. Listing 1-2    Playing a sound file with SndStartFilePlay1-26
  405. Listing 1-3    Determining whether sound recording equipment is available1-27
  406. Listing 1-4    Recording through the sound recording dialog box1-28
  407. Listing 1-5    Recording a sound resource1-29
  408. Listing 1-6    Recording a sound file1-31
  409. Listing 1-7    Checking for speech generation capabilities1-31
  410. Listing 1-8    Using SpeakString to generate speech from a string1-32
  411. Listing 1-9    Generating speech synchronously1-33
  412. Listing 1-10    Stopping speech generated by SpeakString1-34
  413. Chapter 2    Sound Manager2-1
  414.  
  415. Figure 2-1    The position of the Sound Manager2-6
  416. Figure 2-2    A graph of a wave table2-9
  417. Figure 2-3    Interleaving stereo sample points2-11
  418. Figure 2-4    The structure of 'snd ' resources2-74
  419. Figure 2-5    The location of the data offset bit2-75
  420. Figure 2-6    The general structure of a chunk2-83
  421. Figure 2-7    A sample AIFF-C file2-88
  422. Figure 2-8    The 'snd ' resource type2-155
  423. Figure 2-9    The sound resource header2-156
  424. Table 2-1    Sample rates2-16
  425. Table 2-2    Frequencies expressed as MIDI note values2-43
  426. Listing 2-1    Creating a sound channel2-20
  427. Listing 2-2    Reinitializing a sound channel2-24
  428. Listing 2-3    Disposing of memory associated with a sound channel2-25
  429. Listing 2-4    Halving the frequency of a sampled sound2-26
  430. Listing 2-5    Changing the amplitude of a sound channel2-27
  431. Listing 2-6    Getting the amplitude of a sound in progress2-28
  432. Listing 2-7    Adding a channel to a group of channels to be synchronized2-30
  433. Listing 2-8    Setting left and right volumes2-32
  434. Listing 2-9    Determining if stereo capability is available2-34
  435. Listing 2-10    Determining if the enhanced Sound Manager is present2-35
  436. Listing 2-11    Testing for multichannel play capability2-36
  437. Listing 2-12    Testing for play-from-disk capability2-37
  438. Listing 2-13    Determining whether a sound channel is paused2-39
  439. Listing 2-14    Determining the number of allocated sound channels2-40
  440. Listing 2-15    Using the freqDurationCmd command2-42
  441. Listing 2-16    Installing a sampled sound as a voice in a channel2-44
  442. Listing 2-17    Looping an entire sampled sound2-45
  443. Listing 2-18    Issuing a callback command2-48
  444. Listing 2-19    Defining a callback procedure2-48
  445. Listing 2-20    Checking whether a callback procedure has executed2-49
  446. Listing 2-21    Stopping a sound that is playing asynchronously2-50
  447. Listing 2-22    Starting an asynchronous sound play2-50
  448. Listing 2-23    Defining a completion routine2-52
  449. Listing 2-24    Defining a data structure to track many sound channels2-54
  450. Listing 2-25    Marking a channel for disposal2-55
  451. Listing 2-26    Disposing of channels that have been marked for disposal2-55
  452. Listing 2-27    Playing a sound resource2-57
  453. Listing 2-28    Obtaining the offset in bytes to a sound header2-58
  454. Listing 2-29    Converting an offset to a sound header into a pointer to a sound header2-60
  455. Listing 2-30    Playing a sound using the bufferCmd command2-62
  456. Listing 2-31    Finding a chunk in a sound file2-63
  457. Listing 2-32    Loading a chunk from a sound file2-65
  458. Listing 2-33    Compressing audio data2-67
  459. Listing 2-34    Setting up double buffers2-70
  460. Listing 2-35    Defining a doubleback procedure2-73
  461. Listing 2-36    A format 1 'snd ' resource2-76
  462. Listing 2-37     A format 1 'snd ' resource containing sampled-sound data2-77
  463. Listing 2-38    An 'snd ' resource containing compressed sound data2-78
  464. Listing 2-39    A resource specification2-79
  465. Listing 2-40    A resource specification for the Simple Beep2-79
  466. Listing 2-41    A format 2 'snd ' resource2-81
  467. Chapter 3    Sound Input Manager3-1
  468.  
  469. Figure 3-1    An example of the csParam field for a Status request3-14
  470. Figure 3-2    An example of the csParam field for a Control request3-14
  471. Table 3-1    The sampled sound header format used by SetupSndHeader3-45
  472. Listing 3-1    Recording directly from a sound input device3-7
  473. Listing 3-2    Determining the name of a sound input device3-12
  474. Listing 3-3    Determining some sound input device settings3-12
  475. Chapter 4    Speech Manager4-1
  476.  
  477. Figure 4-1    The speech generation process4-4
  478. Figure 4-2    The Speech Manager and multiple voices4-5
  479. Figure 4-3    MIDI note values and corresponding piano keys4-7
  480. Figure 4-4    An example of pitch range for a voice 4-8
  481. Figure 4-5    Format of a pronunciation dictionary resource4-90
  482. Figure 4-6    Format of a dictionary entry in a dictionary resource4-92
  483. Figure 4-7    Format of a dictionary entry field4-93
  484. Table 4-1    The embedded command syntax structure4-25
  485. Table 4-2    Embedded speech commands4-26
  486. Table 4-3    American English phoneme symbols4-33
  487. Table 4-4    Prosodic control symbols4-34
  488. Table 4-5    Effect of punctuation marks on English-language synthesizers4-35
  489. Listing 4-1    Checking for speech generation capabilities4-12
  490. Listing 4-2    Speaking text with a speech channel4-13
  491. Listing 4-3    Getting a description of a voice4-15
  492. Listing 4-4    Changing the speech rate and pitch4-16
  493. Listing 4-5    Pausing and continuing speech production4-18
  494. Listing 4-6    Setting up a speech channel for callbacks4-21
  495. Listing 4-7    Installing a word callback procedure4-21
  496. Listing 4-8    A typical word callback procedure4-22
  497. Listing 4-9    Installing a pronunciation dictionary resource into a speech channel4-37
  498. Listing 4-10    A sample pronunciation dictionary resource4-38
  499. Chapter 5    Sound Components5-1
  500.  
  501. Figure 5-1    The component-based sound architecture5-5
  502. Figure 5-2    A component chain for audio hardware that can convert sample rates5-5
  503. Figure 5-3    Mixing multiple channels of sound5-6
  504. Figure 5-4    A sound output device component that can mix sound channels5-7
  505. Listing 5-1    Rez input for a component resource5-11
  506. Listing 5-2    Handling Component Manager selectors5-14
  507. Listing 5-3    Finding the address of a component-defined routine5-14
  508. Listing 5-4    Initializing an output device5-17
  509. Listing 5-5    Getting sound component information5-19
  510. Chapter 6    Audio Components6-1
  511.  
  512. Figure 6-1    The Apple AudioVision 14 Display6-4
  513. Figure 6-2    The Volumes control panel for the Apple AudioVision 14 Display6-4
  514. About This Book
  515.  
  516.  
  517. This book, Inside Macintosh: Sound, describes the parts of the Macintosh system software that allow you to manage sounds. It describes the services provided by the three principal sound-related system software managers (the Sound Manager, the Sound Input Manager, and the Speech Manager) and shows in detail how your application can record and play back sounds, compress and expand audio data, convert text to speech, and perform other similar operations.
  518. If you are not yet experienced with playing or recording sounds on Macintosh computers, you should begin with the chapter “Introduction to Sound on the Macintosh.” That chapter describes the services provided by the system software and shows how to use the most basic sound-related capabilities of Macintosh computers. It provides complete source code examples illustrating how to record sounds into resources and files, how to play sounds stored in resources and files, and how to convert written text into spoken words. It’s possible that this introductory chapter contains all the information you need to successfully integrate sound into your application.
  519. Once you are familiar with basic sound recording and production on Macintosh computers, you might want to read other chapters in this book. The chapter “Sound Manager” provides complete information about sound output. It shows how to control sound production at a very low level, how to produce sound asynchronously (that is, while other operations in the computer take place), and how to compress and expand audio data. This chapter also provides complete details about the structure of the two main sound storage formats, sound resources and sound files.
  520. If you need more control over the sound recording process than is offered by the basic recording functions described in the chapter “Introduction to Sound on the Macintosh,” you need to read the chapter “Sound Input Manager.” That chapter shows how to record sound without displaying the sound recording dialog box or to interact directly with a sound input device driver.
  521. The chapter “Speech Manager” shows how you can convert written text into speech. You’ll need to read this chapter if you want to convert arbitrary blocks of text (such as very large buffers of text) into spoken words, or if you need to gain very fine control over speech production (for example, to synchronize speech production with other activities, or to use customized pronunciation dictionaries).
  522. The chapter “Sound Components” describes how to write sound components. The Sound Manager uses sound components to manipulate audio data or to communicate with sound output devices. You need to read this chapter only if you are developing a new sound output device or want to use a custom audio data compression and expansion scheme.
  523. The chapter “Audio Components” describes how to write audio components. The Sound Manager uses audio components to adjust volumes or other settings of a sound output device when the device contains multiple output ports that can be independently controlled by software. You need to read this chapter only if you are developing a new sound output device that contains several sound-producing ports (such as both speakers and headphones).
  524.  
  525. Format of a Typical Chapter
  526.  
  527. Almost all chapters in this book follow a standard structure. For example, the chapter “Sound Input Manager” contains these sections:
  528. n    “About the Sound Input Manager.” This section provides an overview of the features provided by the Sound Input Manager.
  529. n    “Using the Sound Input Manager.” This section describes the tasks you can accomplish using the Sound Input Manager. It describes how to use the most common routines, gives related user interface information, provides code samples, and supplies additional information.
  530. n    “Sound Input Manager Reference.” This section provides a complete reference for the Sound Input Manager by describing the constants, data structures, routines, and resources it uses. Each routine description also follows a standard format, which presents the routine declaration followed by a description of every parameter of the routine. Some routine descriptions also give additional descriptive information, such as assembly-language information or result codes.
  531. n    “Summary of the Sound Input Manager.” This section provides the Pascal and C interfaces for the constants, data structures, routines, and result codes associated with the Sound Input Manager. It also includes relevant assembly-language interface information.
  532.  
  533. Conventions Used in This Book
  534.  
  535. Inside Macintosh uses special conventions to present certain types of information. Words that require special treatment appear in specific fonts or font styles. Certain information, such as parameter blocks, appears in special formats so that you can scan it quickly.
  536. Special Fonts
  537.  
  538. All code listings, reserved words, and the names of actual data structures, constants, fields, parameters, and routines are shown in Courier (this is Courier).
  539. Words that appear in boldface are key terms or concepts and are defined in the glossary.
  540. Types of Notes
  541.  
  542. There are several types of notes used in this book.
  543. Note
  544. A note like this contains information that is interesting but possibly not essential to an understanding of the main text. (An example appears on page 1-6.)u
  545. IMPORTANT
  546. A note like this contains information that is essential for an understanding of the main text. (An example appears on page 1-9.)s
  547. sWARNING
  548. Warnings like this indicate potential problems that you should be aware of as you design your application. Failure to heed these warnings could result in system crashes or loss of data. (An example appears on page 2-24.)s
  549. Assembly-Language Information
  550.  
  551. Inside Macintosh provides information about the registers for specific routines in this format:
  552. Registers on entry        
  553. A0    Contents of register A0 on entry    
  554.  
  555. Registers on exit        
  556. D0    Contents of register D0 on exit    
  557.  
  558. In the “Assembly-Language Summary” section at the end of each chapter, Inside Macintosh presents information about the fields of data structures in this format:0    what    word    event code    
  559. 2    message    long    event message    
  560. 6    when    long    ticks since startup    
  561.  
  562. The left column indicates the byte offset of the field from the beginning of the data structure. The second column shows the field name as defined in the MPW Pascal interface files; the third column indicates the size of that field. The fourth column provides a brief description of the use of the field. For a complete description of each field, see the discussion of the data structure in the reference section of the chapter.
  563. In addition, Inside Macintosh presents information about the fields of a parameter block in this format:
  564. Parameter block                
  565. ´    inAndOut    Integer    Input/output parameter.    
  566. ¨    output1    Ptr    Output parameter.    
  567. Æ    input1    Ptr    Input parameter.    
  568.  
  569. The arrow in the far left column indicates whether the field is an input parameter, output parameter, or both. You must supply values for all input parameters and input/output parameters. The routine returns values in output parameters and input/output parameters.
  570. The second column shows the field name as defined in the MPW Pascal interface files; the third column indicates the Pascal data type of that field. The fourth column provides a brief description of the use of the field. For a complete description of each field, see the discussion that follows the parameter block or the description of the parameter block in the reference section of the chapter.
  571.  
  572. Development Environment
  573.  
  574. The system software routines described in this book are available using Pascal, C, or assembly-language interfaces. How you access these routines depends on the development environment you are using. When showing system software routines, this book uses the Pascal interfaces available with the Macintosh Programmer’s Workshop (MPW). However, the chapters “Sound Components” and “Audio Components” use C interfaces, because Pascal interfaces are not currently available.
  575. All code listings in this book are shown in Pascal or C. They show methods of using various routines and illustrate techniques for accomplishing particular tasks. All code listings have been compiled and, in most cases, tested. However, Apple Computer, Inc. does not intend for you to use these code samples in your application.
  576. This book occasionally illustrates concepts by referring to a sample application called SurfWriter. This application is not an actual product of Apple Computer, Inc. This book also uses the names SurfBoard and WaveMaker to refer to sample sound output and input devices. These devices are not actual products of Apple Computer, Inc.
  577.  
  578.  
  579. For More Information
  580.  
  581. APDA is Apple’s worldwide source for over three hundred development tools, technical resources, training products, and information for anyone interested in developing applications on Apple platforms. Customers receive the quarterly APDA Tools Catalog featuring all current versions of Apple and the most popular third-party development tools. Ordering is easy; there are no membership fees, and application forms are not required for most of our products. APDA offers convenient payment and shipping options, including site licensing.
  582. To order products or to request a complimentary copy of the APDA Tools Catalog, contact 
  583. APDA 
  584. Apple Computer, Inc. 
  585. P.O. Box 319
  586. Buffalo, NY 14207-0319Telephone    800-282-2732 (United States)
  587. 800-637-0029 (Canada)
  588. 716-871-6555 (International)    
  589. Fax    716-871-6511     
  590. AppleLink    APDA    
  591. America Online    APDAorder    
  592. CompuServe    76666,2405    
  593. Internet    APDA@applelink.apple.com    
  594.  
  595. If you provide commercial products and services, call 408-974-4897 for information on the developer support programs available from Apple.
  596. For information of registering signatures, file types, and other technical information, contact
  597. Macintosh Developer Technical Support
  598. Apple Computer, Inc.
  599. 20525 Mariani Avenue, M/S 303-2T
  600. Cupertino, CA 95014-6299
  601. Listing 1-0
  602. Table 1-0
  603. Introduction to Sound on the Macintosh
  604. Contents
  605. About Sound on Macintosh Computers1-4
  606. Sound Capabilities1-4
  607. Sound Production1-9
  608. Sound Recording1-15
  609. Sound Resources1-17
  610. Sound Files1-18
  611. Speech Generation1-20
  612. The User Interface for Sound1-23
  613. Using Sound on Macintosh Computers1-24
  614. Producing an Alert Sound1-24
  615. Playing a Sound Resource1-25
  616. Playing a Sound File 1-26
  617. Checking For Sound-Recording Equipment1-27
  618. Recording a Sound Resource1-28
  619. Recording a Sound File1-31
  620. Checking For Speech Capabilities1-31
  621. Generating Speech From a String1-32
  622. Sound Reference1-34
  623. Routines1-34
  624. Playing Sounds1-34
  625. Recording Sounds1-38
  626. Generating and Stopping Speech1-41
  627. Summary of Sound1-44
  628. Pascal Summary1-44
  629. Constants1-44
  630. Routines1-44
  631. C Summary1-45
  632. Constants1-45
  633. Routines1-46
  634. Result Codes1-47
  635. Introduction to Sound on the Macintosh
  636. This chapter provides an introduction to managing sound on Macintosh computers. It’s intended to help you quickly get started integrating sound into your application. This chapter introduces the concepts described in detail throughout the rest of this book and provides source code examples that show you how to use the most basic sound-related capabilities of Macintosh computers. These examples use the Sound Manager to play sounds, the Sound Input Manager to record sounds, and the Speech Manager to convert text strings into spoken words.
  637. Even if your application is not specifically concerned with creating or playing sounds, you can often improve your application at very little programming expense by using these system software services to integrate sound or speech into its user interface. For example, you might use the techniques described in this chapter to
  638. n    play a sound to alert the user that a lengthy spreadsheet calculation is completed
  639. n    provide voice annotations for a word-processing document
  640. n    read aloud the text string that is displayed in a dialog box
  641. If you want to use sound in these simple ways, this chapter will probably provide all the information you need. The Sound Manager, Sound Input Manager, and Speech Manager provide high-level routines that make it very easy to play or record sounds without knowing very much about how sounds are stored or produced electronically.
  642. If, on the other hand, you are writing an application that is primarily concerned with sound, you should read this chapter and some of the remaining chapters in this book. You also need to read those chapters if you want to play computer-generated tones without using sound resources or sound files, play sounds asynchronously, play sounds at different pitches, record sounds without using the standard sound recording interface, or customize the quality of speech output to make it easier to understand.
  643. To benefit most from this chapter, you should already be familiar with simple resource and file management, discussed in the chapters “Resource Manager” in Inside Macintosh: More Macintosh Toolbox and “Introduction to File Management” in Inside Macintosh: Files. In particular, this chapter does not explain how to open or close resource or data files, although it does provide source code examples that demonstrate how to play a sound from, or record a sound to, a resource or data file that is already open.
  644. This chapter begins with an overview of sound on Macintosh computers. It describes the audio capabilities available on all Macintosh computers and some of the capabilities achievable by adding additional hardware and software to Macintosh computers. Then this chapter describes how you can use the available system software routines to
  645. n    play the system alert sound
  646. n    play sounds stored as resources
  647. n    play sampled sounds stored in sound files
  648. n    determine whether a particular Macintosh computer is capable of recording sounds
  649. n    record sounds into resources
  650. n    record sounds into sound files
  651. n    convert text strings into spoken words
  652. For your convenience, this chapter also includes a reference section containing complete descriptions of the routines used to perform these tasks, and both Pascal and C language summaries. All of the routines in the reference section of this chapter are also in the reference sections of the chapter that describes the manager they are part of.
  653.  
  654. About Sound on Macintosh Computers
  655.  
  656. The Macintosh hardware and system software provide a standard and extensible set of capabilities for producing and recording sounds. No matter what kind of application you are developing, you can use these capabilities to enrich your application, often at very little programming expense. For example, you might allow users to attach voice annotations to documents or to other collections of data. Or, you might play a certain sound to signal that some operation has completed.
  657. This section provides a general overview of the sound input and output capabilities available on Macintosh computers. It defines some of the concepts used throughout this book and describes how sounds can be stored by your application. This section also describes the standard ways of representing sounds in the Macintosh graphical user interface.
  658. Sound Capabilities
  659.  
  660. The Macintosh family of computers provides sound input and output capabilities that far exceed the capabilities of most other personal computers. The principal reason for this is that the hardware and software aspects of creating or recording sounds are more tightly integrated with one another than they are on other personal computers. 
  661. Figure 1-1 illustrates the basic audio hardware and the sound-related system software that are now standard on all Macintosh computers.
  662. Figure 1-1    Basic sound capabilities on Macintosh computers
  663.  
  664. The audio hardware includes an internal speaker (for producing sounds), a microphone (for recording sounds), and one or more integrated circuits that convert digital data to analog signals, or analog signals to digital data. The actual integrated circuits that perform the conversion of digital to analog data (and vice versa) vary among different models of Macintosh computers. What’s important is that, together with the available sound-related system software, the basic audio hardware provides a wide range of sound input and output capabilities, including
  665. n    playback of digitally recorded (that is, sampled) sounds
  666. n    playback of simple sequences of notes or of complex waveforms
  667. n    recording of sampled sounds
  668. n    conversion of text to spoken words
  669. n    mixing and synchronization of multiple channels of sampled sounds
  670. n    compression and decompression of sound data to minimize storage space
  671. In general, you’ll interact directly with the system software that provides these and other capabilities. The Macintosh sound architecture includes three principal system software services:
  672. n    The Sound Manager provides the ability to play sounds through the speaker. It also provides an extensive set of tools for manipulating sounds. You can use the Sound Manager to alter virtually any characteristic of a sound, such as its loudness, pitch, timbre, and duration. You can also use the Sound Manager to compress sounds so that they occupy less disk space. The Sound Manager can work with sounds stored in resources or in a file’s data fork. It can also play sounds that are generated dynamically (and not necessarily stored on disk).
  673. n    The Sound Input Manager provides the ability to record sounds through a microphone or other sound input device. It manages the standard sound recording dialog box (shown in Figure 1-12 on page 1-17) and can record sounds into resources or into files.
  674. n    The Speech Manager provides the ability to convert written text into spoken words. You might use the Speech Manager to read aloud a block of text that for various reasons cannot be sampled (perhaps the amount of text is too large to be recorded and then replayed, or perhaps the text itself is generated dynamically by the user). The Speech Manager allows you to select from among a number of different voices, alter some of the readback characteristics (such as speech, pitch, and volume), and provide custom pronunciation dictionaries.
  675. The basic sound hardware and system software also provide the ability to integrate and synchronize sound production with the display of other types of information, such as video and still images. For example, QuickTime uses the Sound Manager to handle all the sound data in a QuickTime movie.
  676. It’s very easy for users to enhance the quality of the sounds they play back or record by substituting different speakers or microphones for the ones built into a Macintosh computer. All current Macintosh computers include a stereo sound output jack that allows users to add high quality speakers (such as the AppleDesign Powered Speakers). A user can also substitute a higher quality microphone for the one supplied with the computer. Figure 1-2 illustrates a slightly better audio configuration than the one shown in Figure 1-1.
  677. Figure 1-2    Enhanced sound capabilities on Macintosh computers
  678.  
  679. Note that the enhanced sound input and output capabilities shown in Figure 1-2 are provided entirely by the improved hardware. The system software (in particular, the Sound Manager and the Sound Input Manager) can support both the built-in audio hardware and any external hardware connected to the built-in audio jacks.
  680. It’s possible to enhance the audio capabilities of a Macintosh computer even further. For example, a user can add a NuBus™ expansion card that contains very high quality digital signal processing (DSP) circuitry, together with sound input or output hardware. These cards typically bypass the standard Macintosh sound circuitry altogether and therefore require additional software (a device driver) to work with the Sound Manager or the Sound Input Manager. The system software is, however, designed to make it easy for developers to add software to drive their sound output or sound input devices.
  681. A user can also enhance the audio capabilities of a Macintosh computer by adding a MIDI interface to one of its serial ports. MIDI (the Musical Instrument Digital Interface) is a standard protocol for sending audio data and commands to digital devices. A user can connect any MIDI devices (such as synthesizers, drum machines, or lighting controllers) to a Macintosh computer through the MIDI interface. Apple Computer supplies a software driver, the MIDI Manager, to control the flow of MIDI data and commands through the MIDI interface.
  682. Note
  683. The MIDI Manager is not documented in this book. For complete information about the MIDI Manager, contact APDA.u
  684. Figure 1-3 illustrates a very high capability sound and music configuration built around a Macintosh computer. This enhanced hardware and system software configuration allows users to run digital sound editing or recording applications and MIDI sequencing applications.
  685. Figure 1-3    High quality sound capabilities on Macintosh computers
  686.  
  687. It’s possible to enhance the sound environment on a Macintosh computer by adding software alone, for example by adding custom sound compression/decompression components (codecs). Apple Computer supplies codecs that can handle 3:1 and 6:1 compression and expansion, which are suitable for most audio requirements. For special purposes, however, it might be advantageous to use other compression and expansion ratios or algorithms. The Sound Manager can use any available codec to handle compression and expansion of audio data.
  688. More generally, the Sound Manager supports arbitrary modifications on sound data using stand-alone code resources known as sound components. A sound component can perform one or more signal-processing operations on sound data. For example, the Sound Manager includes sound components for compressing and decompressing sound data (as described in the previous paragraph) and for converting sample rates. Sound components have a standard programming interface and local storage, which allows them to be hooked together in series to perform complex tasks. For instance, to play an 11 kHz compressed sampled sound on a Macintosh II computer, the Sound Manager needs to expand the compressed data into audio samples, convert the samples from 11 kHz to 22 kHz, mix the samples with any other sounds that are playing, and then send the mixed samples to the available audio hardware (in this case, the Apple Sound Chip). The Sound Manager uses four different sound components to accomplish this task, as shown in Figure 1-4.
  689. Figure 1-4    A sound component chain
  690.  
  691. Except for the lowest-level components that communicate directly with hardware (here, the Apple Sound Chip), the components of this chain operate solely on a stream of bytes. This allows Apple and other developers to create sound components that operate independently of the actual sound-producing hardware available on a particular Macintosh computer. This also allows the Sound Manager to modify the component chain used at any time according to the actual capabilities of the output hardware. For example, a digital signal processing card might be able to do rate conversion internally. In that case, the Sound Manager can bypass the rate conversion component and send the 11 kHz samples directly to the DSP card, as shown in Figure 1-5.
  692. Figure 1-5    A sound component chain with a DSP board
  693.  
  694. In general, an application that wants to produce a sound is unaware of the sound component chain required to produce that sound on the current sound output device. The Sound Manager keeps track of which sound output device the user has selected and constructs a component chain suitable for producing the desired quality of sound on that device. As a result, even though the capabilities of the available sound output hardware can vary greatly from one Macintosh computer to another, the Sound Manager ensures that a given chunk of audio data always sounds as good as possible on the available sound hardware. This means that you can use the same code to play sounds, regardless of the actual sound-producing hardware that is available on a particular machine.
  695. The Sound Manager provides sound components for modifying and producing sounds on the built-in audio hardware and on any hardware attached to the sound output jack. The Macintosh sound architecture currently allows you to add sound components for two special purposes: to support alternate compression and decompression algorithms and to support third-party audio hardware. See the chapter “Sound Components” in this book for information on developing codecs and sound output device components.
  696. IMPORTANT
  697. You don’t need to know how to develop sound components simply to play or record sounds on Macintosh computers using the available sound output or input devices.s
  698. The following sections describe in greater detail the operations of the Sound Manager, the Sound Input Manager, and the Speech Manager. You’ll use the Sound Manager to produce sounds, the Sound Input Manager to record sounds, and the Speech Manager to generate speech from text.
  699. Sound Production
  700.  
  701. A Macintosh computer produces sound when the Sound Manager sends some data through a sound channel to the available audio hardware, usually at the request of an application. The audio hardware is a digital-to-analog converter (DAC) that translates digital sound data into analog audio signals. Those signals are then sent to the internal speaker, to a sound output connector (to which the user can connect headphones, external speakers, or sound amplification equipment), or to other sound output hardware.
  702. The DAC in Macintosh Plus and Macintosh SE computers is a Sony sound chip. The Macintosh II, Macintosh Portable, Macintosh PowerBook and Macintosh Quadra families of computers contain two Sony sound chips (to provide stereo output capability) as well as the Apple Sound Chip (ASC), a customized chip that provides enhanced audio output characteristics as well as emulation capabilities for the earlier sound hardware.
  703. Some recent models of Macintosh computers contain built-in sound hardware that extends the Apple Sound Chip’s features. For example, Macintosh computers with built-in microphones include the Enhanced Apple Sound Chip (EASC). Some Macintosh computers contain DSP chips that provide very high-quality sound (16-bit stereo sound, at rates up to 44 kHz). There are also NuBus expansion cards available from third-party developers that provide other audio DAC hardware.
  704. A user can select a sound output device or control characteristics of the selected device through the Sound Out control panel, shown in Figure 1-6. The available sound output devices are listed in the center of the panel. In this case, two sound output devices are attached to the computer, the built-in speaker and a speaker attached to the SurfBoard DSP card. The highlighted icon shows which device is the current sound output device. All sounds produced by the Sound Manager are sent to that device for playback, unless you specify some other device when creating a sound channel. (See the description of SndNewChannel in the chapter “Sound Manager” for details on specifying an output device explicitly.)
  705. Figure 1-6    The Sound Out control panel
  706.  
  707. Note
  708. This book shows the Sound control panels introduced with version 3.0 of the Sound Manager. Users can use the pop-up menu at the top of the panel to select one of four or more subpanels (Alert Sounds, Sound In, Sound Out, and Volumes). It’s possible to add new subpanels to the Sound control panel. See the chapter on control panel extensions in the book Inside Macintosh: Operating System Utilities.u
  709. You can play a sound by calling a Sound Manager routine such as SysBeep (to play the system alert sound), SndPlay (to play a sound stored in memory), or SndStartFilePlay (to play a sound stored in a file). The Sound Manager then issues one or more sound commands to the audio hardware. A sound command is an instruction to produce sound, modify sound, or otherwise assist in the overall process of sound production.
  710. To ensure that sound commands are issued in the correct order, the Sound Manager uses a structure called a sound channel to store commands. A sound channel is associated with a first-in, first-out (FIFO) queue of sound commands. Queued commands are sent to the sound hardware through a sound output device component, a component that manages the last stage of communication with the audio hardware. Figure 1-7 shows how your application communicates, through the Sound Manager and the sound output device component, with the current sound output device.
  711. Figure 1-7    The relation of the Sound Manager to the audio hardware
  712.  
  713. Note
  714. Note
  715. This chapter does not discuss sound commands or channels in detail, because you do not need to know about these details to play sound data stored in sound resources or sound files. This chapter describes only how to play and record sampled sounds. For more information on sound channels and sound commands, see the chapter “Sound Manager” in this book.u
  716. You can play sounds either synchronously or asynchronously. When you play a sound synchronously, the Sound Manager alone has control over the CPU while it executes commands in a sound channel. Your application does not continue executing until the sound has finished playing. When you play a sound asynchronously, your application can continue other processing while the sound is playing. This chapter shows how to play sounds only synchronously. To learn how to play sounds asynchronously, see the chapter “Sound Manager” in this book.
  717. Sometimes it is necessary to bypass the queue of sound commands. If, for example, you want to stop all sound production on a particular channel immediately, it would be counterproductive to put the command into the sound channel because that command wouldn’t be processed until any others already in the queue were processed. You can send sound commands directly to the hardware component, as shown in Figure 1-8.
  718. When you bypass the sound channel in this way, any commands that are already queued but not yet sent to the sound output device component remain queued. You can, however, flush the channel at any time by sending the Sound Manager the appropriate request.
  719. Figure 1-8    Bypassing the command queue
  720.  
  721. It’s possible to have several channels of sound open at one time. The Sound Manager (using a sound-mixing component called the Apple Mixer component) mixes together the data coming from all open sound channels and sends a single stream of sound data to the current sound output device. This allows a single application to play two or more sounds at once. It also allows multiple applications to play sounds at the same time, as illustrated in Figure 1-9.
  722. Figure 1-9    Mixing multiple channels of sampled sound
  723.  
  724. The Sound Manager was first released for all Macintosh computers as part of system software version 6.0. System software versions 6.0.7 and later include an enhanced Sound Manager (that is, version 2.0) that provides routines for continuous play from disk, sound mixing, and audio compression and expansion. System software versions 6.0.7 and later also include the Sound Input Manager, which allows for recording sounds through either a built-in microphone or some other sound input device.
  725. More recent versions of the Sound Manager significantly improve the performance of the Sound Manager’s operations and extends its capabilities. Version 3.0 of the Sound Manager is as much as two to three times more efficient than previous versions, which allows your application to do more processing while a sound is playing. In addition, version 3.0 of the Sound Manager provides three important new capabilities:
  726. n    Support for 16-bit audio samples. Versions of the Sound Manager earlier than version 3.0 support only 8-bit monophonic or stereo audio samples with sample rates up to 22 kHz. The Sound Manager version 3.0 supports 16-bit stereo audio samples with sample rates up to 64 kHz, thereby allowing your application to produce CD-quality sound. Moreover, the Sound Manager version 3.0 automatically converts 16-bit samples into 8-bit samples on Macintosh computers that do not have the hardware to output 16-bit sounds.
  727. n    Support for non-Apple audio hardware. The Sound Manager version 3.0 and later use a sound architecture that allows support for third-party audio hardware. This allows a user to install audio hardware capable of recording and producing CD-quality sound. Versions 3.0 and later also include a new Sound control panel that allows the user to redirect sound output to any available audio hardware.
  728. n    Support for plug-in codecs. Versions of the Sound Manager earlier than version 3.0 support audio compression and expansion only at ratios of 3:1 and 6:1. The Sound Manager version 3.0 provides support for other compressed audio data formats by allowing plug-in audio compression and expansion components (or codecs).
  729. You provide support for your own sound output devices or for your own compression and decompression algorithms by writing an appropriate sound component. See the chapter “Sound Components” later in this book for complete details.
  730. The Sound Manager version 3.0 is supported only on Macintosh computers with an ASC or comparable hardware. In particular, the Sound Manager version 3.0 is not supported on Macintosh Classic, Macintosh Plus, or Macintosh SE computers. As a result, you should always test whether the specific capabilities you want to use are present before attempting to use them. You can use the Gestalt function to do this, as illustrated in “Checking For Sound-Recording Equipment” beginning on page 1-27 and in “Checking For Speech Capabilities” beginning on page 1-31.
  731. This book describes the capabilities and programming interfaces of version 3.0 of the Sound Manager. Many of the techniques described here can also be used with earlier versions of the Sound Manager, but some cannot. Make sure to test your application thoroughly with all versions of the Sound Manager you want to run under.
  732. Sound Recording
  733.  
  734. The Sound Input Manager provides the ability to record and digitally store sounds in a device-independent manner. You can create a resource or a file containing a recorded sound simply by calling either the SndRecord function or the SndRecordToFile function. You can then use the recorded sound in any way appropriate to your application.
  735. The sound input and storage routines can be used with any available sound input hardware for which there is an appropriate device driver. A user can select from among the available sound input devices through the Sound In control panel, shown in Figure 1-10.
  736. Figure 1-10    The Sound In control panel
  737.  
  738. The available sound input devices are listed in the center of the panel. The control panel lists a device if its driver has previously registered itself with the Sound Input Manager and has provided a name and device icon. In Figure 1-10, two sound input devices are available, a device named Built-in and a device named WaveMaker. The highlighted icon shows which device is the current sound input device.
  739. The Alert Sounds control panel lists the available system alert sounds, as illustrated in Figure 1-11.
  740. Figure 1-11    The Alert Sounds control panel
  741.  
  742. The Alert Sounds control panel also includes two buttons, Add and Remove. These buttons allow the user to add sounds to and remove sounds from the list of available system alert sounds. The Add button is used to record a new alert sound and add it to the list. Clicking the Add button causes the Sound Input Manager to display a sound recording dialog box (described later in this section). Clicking the Remove button causes the Sound Input Manager to remove the selected alert sound from the list. The user can achieve the same effect by selecting a sound and then choosing the Clear command in the Edit menu. If no sound input drivers are installed in the system, these two buttons do not appear.
  743. If the user records a sound using the Alert Sounds control panel, the recorded sound is saved as a resource of type 'snd ' in the System file. That sound then appears in the list of available alert sounds. Note that the Alert Sounds control panel supports the standard Edit menu commands on sounds stored in the System file. The Cut command copies the selected sound to the Clipboard and removes it from the list of system alert sounds. The Copy command just copies the selected sound to the Clipboard. The Paste command takes a sound copied from the Clipboard and places it in the list of available alert sounds. If your application allows users to manipulate sound resources, it should support the copying and pasting of sound resources through the Clipboard. However, the Undo command does not work with sound-related editing operations.
  744. The Sound Input Manager provides two high-level routines that allow your application to record sounds from the user and store them in memory or in a file. When you call either SndRecord or SndRecordToFile, the Sound Input Manager presents a sound recording dialog box to the user, illustrated in Figure 1-12.
  745. Figure 1-12    The sound recording dialog box
  746.  
  747. Using the controls in this dialog box, the user can start, pause, resume, and stop recording on the currently selected sound input device. The user can also play back the recorded sound. The time indicator bar provides an indication of the current length of the recorded sound.
  748. When the user clicks the Save button after initiating a recording from the Sound control panel, another dialog box appears asking the user to give the sound a name. Unless the user cancels the save operation at that point, the Sound control panel saves the recorded sound into a sound resource in the System file. Note that if your application can save recorded sound resources, the SndRecord function does not present the dialog box that allows the user to name the sound and does not automatically save the recorded sound into a resource file. Your application must provide code to accomplish these tasks.
  749. Sound Resources
  750.  
  751. Resources of type 'snd ' (also called sound resources) can contain both sound commands and sound data, and are widely used by sound-producing applications. These resources provide a simple and portable way for you to incorporate sounds into your application. For example, the sounds that a user can select in the Sound control panel as the system alert sound are stored in the System file as 'snd ' resources. The user can select the current system alert sound with the Alert Sounds control panel, as illustrated in Figure 1-11. More generally, you can load a sound resource into memory and then play it by calling the SndPlay function.
  752. Note
  753. If you do not use the sound-recording routines provided by the Sound Input Manager, you must know the structure of 'snd ' resources before you can create them. For information on this, see the chapter “Sound Manager” in this book. You can also use the SetupSndHeader function, described in the chapter “Sound Input Manager” in this book, to help you create an 'snd ' resource.u
  754. The Sound Manager can read sound resources in two formats, format 1 or format 2. However, the format 2 'snd ' resource is obsolete, so your application should use format 1 'snd ' resources. For more information on the differences between format 1 and format 2 'snd ' resources, see the chapter “Sound Manager” in this book.
  755. The format 1 'snd ' resource is the most general kind of sound resource. A format 1 'snd ' resource can contain a sequence of Sound Manager commands and associated sound data (such as wave-table data or a sampled sound header that both describes a digitally recorded sound and includes the sampled-sound data itself). Your application can produce sounds simply by passing a handle to that resource to the SndPlay function, which opens a sound channel and sends the commands and data contained in the resource into the channel. Alternatively, a format 1 'snd ' resource might contain a sequence of commands that describe a sound, without providing any other sound data. For example, such a resource could contain a command that alters the amplitude (or loudness) of sound playing on a channel. In this case, your application can use the SndPlay function to execute the commands on any channel.
  756. Sound Files 
  757.  
  758. Although most sampled sounds that you want your application to produce can be stored as sound resources, there are times when it is preferable to store sounds in sound files. For example, it is usually easier for different applications to share files than it is to share resources. So, if you want your application to play a sampled sound created by another application (or if you want other applications to be able to play a sampled sound created by your application), it might be better to store the sampled-sound data in a file, not in a resource. Similarly, if you are developing versions of your application that run on other operating systems, you might need a method of storing sounds that is independent of the Macintosh Operating System and its reliance on resources to store data. Generally, it is easier to transfer data stored in data files from one operating system to another than it is to transfer data stored in resources.
  759. There are other reasons you might want to store some sampled sounds in files and not in resources. If you have a very large sampled sound, it might not be possible to create a resource large enough to hold all the audio data. Resources are limited in size by the structure of resource files (and in particular because offsets to resource data are stored as 24-bit quantities). Sound files, however, can be much larger because the only size limitations are those imposed by the file system on all files. If the sampled-sound data for some sound occupies more than about a half megabyte of space, you should probably store the sound as a file.
  760. To address these various needs, Apple and several third-party developers have defined two sampled-sound file formats, known as the Audio Interchange File Format (AIFF) and the Audio Interchange File Format Extension for Compression (AIFF-C). The names emphasize that the formats are designed primarily as data interchange formats. However, you should find both AIFF and AIFF-C flexible enough to use as data storage formats as well. Even if you choose to use a different storage format, your application should be able to convert to and from AIFF and AIFF-C if you want to facilitate sharing of sound data among applications. AIFF format files have file type 'AIFF' and AIFF-C format files have file type 'AIFC'.
  761. Note
  762. Do not confuse AIFF and AIFF-C files (referred to in this chapter as sound files) with Finder sound files. Each Finder sound file contains a sound resource that plays when the user double clicks on the file in the Finder (or selects the file and chooses Open from the File menu). A user can create a Finder sound file by dragging a sound out of the System file, and a user can drag a Finder sound file into the System file to add the file’s sound to the list of available system alert sounds. You can create a Finder sound file by creating a file of type 'sfil' with a creator of 'movr' and placing in the file a single sound resource. You can play such a file by using Resource Manager routines to open the Finder sound file and then by using the SndPlay function to play the single sound resource contained in it.u 
  763. The main difference between the AIFF and AIFF-C formats is that AIFF-C allows you to store either compressed or noncompressed audio data, whereas AIFF allows you to store noncompressed audio data only. The AIFF-C format is more general than the AIFF format and is easier to modify. The AIFF-C format can be extended to handle new compression types and application-specific data. As a result, if your application reads or writes sound files, it should be able to handle both AIFF and AIFF-C files. Table 1-1 summarizes the capabilities of the AIFF and AIFF-C file formats.
  764. Table 1-1    AIFF and AIFF-C capabilities
  765. File
  766. type    Read
  767. sampled    Read
  768. compressed    Write
  769. sampled    Write
  770. compressed    
  771. AIFF    Yes    No    Yes    No    
  772. AIFF-C    Yes    Yes    Yes    Yes    
  773.  
  774. The enhanced Sound Manager includes play-from-disk routines that allow you to play AIFF and AIFF-C files continuously from disk even while other tasks execute. You might think of the play-from-disk routines as providing you with the ability to install a “tape player” in a sound channel. Once the sound begins to play, it continues uninterrupted until it finishes or until an application pauses or stops it.
  775. You can play a sampled sound stored in a file of type AIFF or AIFF-C by opening the file and passing its file reference number to the SndStartFilePlay function. If the file is of type AIFF-C and the data is compressed, then the data is automatically expanded during playback. The SndStartFilePlay function works like the SndPlay function but does not require the entire sound to be in RAM at one time. Instead, the Sound Manager uses two buffers, each of which is smaller than the sound itself. The Sound Manager plays one buffer of sound while filling the other with data from disk. After it finishes playing the first buffer, the Sound Manager switches buffers, and plays data in the second while refilling the first. This double buffering technique minimizes RAM usage at the expense of additional disk overhead. As a result, SndStartFilePlay is ideal for playing very large sounds.
  776. The disk overhead incurred when using SndStartFilePlay is relatively light, and most mass-storage devices currently available for Macintosh computers have response times that are good enough that SndStartFilePlay can retrieve audio data from disk and play a sound without audible gaps. There are no limits on the number of concurrent disk-based sampled-sound playbacks other than those imposed by processor speed and disk capability. On machines with sufficient CPU resources, several continuous playbacks can occur at once. Disk fragmentation can affect the performance of playing sampled-sound files from disk. In addition, playing multiple sounds from the same hard disk may degrade overall performance.
  777. The Sound Manager currently supports continuous play from disk only on certain Macintosh computers. You should use the Gestalt function to determine whether a specific machine supports play from disk. Also, if a sound channel is being used for continuous play from disk, then no other sound commands can be sent to that channel.
  778. Speech Generation
  779.  
  780. The Speech Manager converts text into sound data, which it passes to the Sound Manager to play through the current sound output device. The Speech Manager’s interaction with the Sound Manager is transparent to your application, so you don’t need to be familiar with the Sound Manager to take advantage of the Speech Manager’s capabilities. This section provides an overview of the Speech Manager and outlines the process that the Speech Manager uses to convert text into speech.
  781. Figure 1-13 illustrates the speech generation process. Your application can initiate speech generation by passing a string or a buffer of text to the Speech Manager. The Speech Manager is responsible for sending the text to a speech synthesizer, a component that contains executable code that manages all communication between the Speech Manager and the Sound Manager. A synthesizer is usually contained in a resource in a file within the System Folder. The synthesizer uses built-in dictionaries and pronunciation rules to help determine how to pronounce text. Your application can use the default system voice to generate speech; it can also specify that some other available voice be used for speech generation.
  782. As Figure 1-13 suggests, the Speech Manager is a dispatching mechanism that allows your application to take advantage of the capabilities of whatever speech synthesizers, voices, and hardware are installed. The Speech Manager itself does not do any of the work of converting text into speech; it just provides a convenient programming interface that manages access to speech synthesizers and, indirectly, to the sound hardware. The Speech Manager uses the Component Manager to access whatever speech synthesizers are available and allows applications to take maximum advantage of a computer’s speech facilities without knowing what those facilities are.
  783. Figure 1-13    The speech generation process
  784.  
  785. Note
  786. The Component Manager is described in Inside Macintosh: More Macintosh Toolbox, but you do not need to be familiar with it to use the Speech Manager.u
  787. A speech synthesizer can include one or more voices, as illustrated in Figure 1-14. Just as different people’s voices have different tonal qualities, so too can different voices in a synthesizer. A synthesized voice might sound male or female, and might sound like an adult or child. Some voices sound distinctively synthetic, while others sound more like real people. As speech synthesizing technology develops, the voices that your application can access are likely to sound more and more human. Because the Speech Manager’s routines work on all voices and synthesizers, you will not need to rewrite your application to take advantage of improvements in speech technology.
  788. Figure 1-14    The Speech Manager and multiple voices
  789.  
  790. Any given person has only one voice, but can alter the characteristics of his or her speech in a number of different ways. For example, a person can speak slowly or quickly, and with a low or a high pitch. Similarly, the Speech Manager provides routines that allow you to modify these and other speech attributes, regardless of which voice is in use.
  791. To indicate to the Speech Manager which voice or attributes you would like it to use in generating speech, your application must use a speech channel. A speech channel is a data structure that the Speech Manager uses when processing text; it can be associated with a particular voice and particular speech attributes. Because multiple speech channels can coexist, your application can create several different vocal environments (to simulate a conversation, for example). Because a synthesizer can be associated with only one language and region, your application would need to create a separate speech channel to process each language in bilingual or multilingual text. (Currently, however, only English-producing synthesizers are available.)
  792. Different speech channels can even generate speech simultaneously, subject to processor capabilities and Sound Manager limitations. This capability should be used with restraint, however, because it can be hard for the user to understand any speech when more than one channel is generating speech at a time. Also, your application should in general generate speech only at the specific request of the user and should allow the user to turn off speech output. At the very least, your application should include an option that allows the user to view text instead of hearing it. Some users might have trouble understanding speech generated by the Speech Manager, and others might be hearing-impaired. Even users who are able to clearly understand computer-synthesized speech might prefer to read rather than hear.
  793. In general, your application does not need to know which speech synthesizer it is using. You can obtain a list of all available voices, but in most cases, you do not need to be concerned with which speech synthesizer a voice is associated. Sometimes, however, a speech synthesizer may provide special capabilities beyond that provided by the Speech Manager. For example, a speech synthesizer might allow you to select an option to read numbers in a nonstandard way. The Speech Manager allows you to determine which synthesizer is associated with a voice for these circumstances, and provides hooks that allow your application to take advantage of synthesizer-specific capabilities.
  794. In general, however, your application can achieve the best results by making no assumptions about which synthesizers might be available. The user of a 2 MB Macintosh Classic® might use a synthesizer with low RAM requirements, while the user of a 20 MB Macintosh Quadra 950 might take advantage of a synthesizer that provides better audio quality at the expense of memory usage. The Speech Manager makes it easy to accommodate both kinds of users.
  795. The most basic use of the Speech Manager is to convert a text string into speech. The SpeakString function, described in “Generating Speech From a String” beginning on page 1-32, lets you do this even without allocating a speech channel. The chapter “Speech Manager” in this book describes how you can customize the quality of speech output to make it easier to understand and how you can obtain more control over speech by allocating speech channels and embedding commands within text strings.
  796. The User Interface for Sound
  797.  
  798. As you have seen, the Macintosh system software provides you with a wide array of easy-to-use sound-input and sound-output services. With very little programming, you can
  799. n    play the user’s system alert sound or any sound contained in a sound resource or file
  800. n    record sounds through the available sound-input hardware
  801. n    convert text into speech
  802. The system software has already defined a set of user interface elements and metaphors that are designed to facilitate the integration of sound into the Macintosh graphical user interface. In general, you should use the existing system software services to present the standard interface elements designed by Apple. For example, if you want to have the user record through the available sound-input hardware, you can call the SndRecord function, which displays the sound recording dialog box (shown in Figure 1-12 on page 1-17). That dialog box contains controls that are modelled on the buttons typically found on an audio tape recorder or a video cassette recorder. In this way, the system software draws on the user’s knowledge of how to operate a tape recorder and uses it as a metaphor for recording sounds on Macintosh computers.
  803. The system software also provides visual representations of sounds themselves. In some cases, sounds are represented by their names only, as in the Alert Sounds control panel (shown in Figure 1-11 on page 1-16). In other cases, sounds are represented by icons. For example, the icon for a Finder sound looks like the one shown in Figure 1-15. All Finder sounds are represented by the same icon; they are distinguished from each other by their names.
  804. Figure 1-15    An icon for a Finder sound
  805.  
  806. If the user copies or cuts a sound from the available system alert sounds and then pastes the sound into the Scrapbook, the sound is shown as in Figure 1-16.
  807. Figure 1-16    A sound in the Scrapbook
  808.  
  809. As you can see, the metaphor in both cases is that of a speaker, a sound-producing device familiar to most computer users. If you need to design icons to represent sounds created by your application, you might want to use (or suitably adapt) these existing metaphors. For example, if your application supports document annotations with recorded voices or other sounds, you can display a speaker icon within the document. Clicking or double-clicking the icon should result in playing the sound.
  810. Keep in mind that applications that play sound should allow users to turn off sound output, because there might be users who object to it or environments where it is inappropriate. Also, there might be cultural biases or preferences associated with certain sounds. Thus, if your application plays specific sounds, you should store them as resources, which can be easily modified for local regions, or if they are very large, in sound files, which you can replace easily during localization.
  811.  
  812. Using Sound on Macintosh Computers
  813.  
  814. This section describes the most basic ways of using the Sound Manager, the Sound Input Manager, and the Speech Manager. In particular, it provides source code examples that show how to produce an alert sound, play a sound resource, play a sound file, determine whether your application can access sound recording equipment, record a sound resource, record a sound file, and convert a text string to spoken words.
  815. Producing an Alert Sound
  816.  
  817. You can produce a system alert sound to catch the user’s attention by calling the SysBeep procedure. The SysBeep procedure is a Sound Manager routine that plays the alert sound selected by the user in the Alert Sounds control panel. Here’s an example of calling SysBeep:
  818. IF myErr <> noErr THEN
  819.     SysBeep(30);
  820. You must supply a parameter when you call the SysBeep procedure, even though the Sound Manager ignores that parameter in most cases. All system alert sounds are stored as format 1 'snd ' resources in the System file and are played by the Sound Manager. There is one instance in which the number passed to SysBeep is not ignored: if the user has selected the Simple Beep as the system alert sound on some Macintosh computers (for example, a Macintosh Plus or Macintosh SE), the beep is generated by code stored in ROM rather than by the Sound Manager, and the duration parameter is interpreted in ticks (sixtieths of a second).
  821. The SysBeep procedure has no effect if an application has disabled the system alert sound. You might do this to prevent the system alert sound from interrupting some other sound. For information on enabling and disabling the system alert sound, see the chapter “Sound Manager” in this book.
  822. You should not call the SysBeep procedure at interrupt time, because doing so causes the Sound Manager to attempt to allocate memory and load a resource.
  823. Note
  824. If your primary use of the SysBeep procedure is to alert the user of important or abnormal occurrences, it might be preferable to use the Notification Manager. See the chapter “Notification Manager” in Inside Macintosh: Processes for complete details on alerting the user.u 
  825. Playing a Sound Resource
  826.  
  827. You can play a sound stored in a resource by calling the SndPlay function, which requires a handle to an existing 'snd ' resource. An 'snd ' resource contains sound commands that play the desired sound. The 'snd ' resource might also contain sound data. If it does (as in the case of a sampled sound), that data might be either compressed or noncompressed. SndPlay decompresses the data, if necessary, to play the sound. Listing 1-1 illustrates how to play a sound resource.
  828. Listing 1-1    Playing a sound resource with SndPlay
  829.  
  830. FUNCTION MyPlaySndResource (mySndID: Integer): OSErr;
  831. CONST
  832.     kAsync = TRUE;                                            {for asynchronous play}
  833. VAR
  834.     mySndHandle:                    Handle;                        {handle to an 'snd ' resource}
  835.     myErr:                    OSErr;
  836. BEGIN
  837.     mySndHandle := GetResource('snd ', mySndID);
  838.     myErr := ResError;                                            {remember any error}
  839.     IF mySndHandle <> NIL THEN                                            {check for a NIL handle}
  840.     BEGIN
  841.         HLock(mySndHandle);                                        {lock the sound data}
  842.         myErr := SndPlay(NIL, mySndHandle, NOT kAsync);
  843.         HUnlock(mySndHandle);                                        {unlock the sound data}
  844.         ReleaseResource(mySndHandle);
  845.     END;
  846.     MyPlaySndResource := myErr;                                            {return the result}
  847. END;
  848. When you pass SndPlay a NIL sound channel pointer in its first parameter, the Sound Manager automatically allocates a sound channel (in the application’s heap) and then disposes of it when the sound has completed playing. Note, however, that when your application does pass NIL as the pointer to a sound channel, the third parameter to SndPlay is ignored; the sound plays synchronously even if you specify that you want it to play asynchronously.
  849. IMPORTANT
  850. The handle you pass to SndPlay must be locked for as long as the sound is playing.s
  851. Playing a Sound File 
  852.  
  853. You can initiate and control a playback of sampled sounds stored in a file using the SndStartFilePlay, SndPauseFilePlay, and SndStopFilePlay functions. You use SndStartFilePlay to initiate the playing of a sound file. If you allocate your own sound channel and specify that play be asynchronous, you can then use the SndPauseFilePlay and SndStopFilePlay functions to pause, resume, and stop sound files that are playing. The chapter “Sound Manager” in this book describes these two functions in detail.
  854. To play a sampled sound that is contained in a file, you pass SndStartFilePlay the file reference number of the file to play. The sample should be stored in either AIFF or AIFF-C format. If the sample is compressed, it is automatically expanded during playback. If you specify NIL as the sound channel, then SndStartFilePlay allocates memory for a channel internally. Listing 1-2 defines a function that plays a file specified by its file reference number.
  855. Listing 1-2    Playing a sound file with SndStartFilePlay
  856.  
  857. FUNCTION MyPlaySoundFile (myFileRefNum: Integer): OSErr;
  858. CONST
  859.     kAsync = TRUE;                                    {for asynchronous play}
  860.     kBufferSize = 20480;                                    {20K play buffer}
  861. VAR
  862.     myErr:            OSErr;
  863. BEGIN
  864.     myErr := SndStartFilePlay(NIL, myFileRefNum, 0, kBufferSize,
  865.                                         NIL, NIL, NIL, NOT kAsync);
  866.     MyPlaySoundFile := myErr;
  867. END;
  868. To allow the Sound Manager to handle all memory allocation automatically, you should pass NIL as the first and fifth parameters to SndStartFilePlay, as done in Listing 1-2. The first NIL specifies that you want SndStartFilePlay to allocate a sound channel itself. The NIL passed as the fifth parameter specifies that SndStartFilePlay should automatically allocate buffers to play the sound. The SndStartFilePlay function then allocates two buffers, each half the size specified in the fourth parameter; if the fourth parameter is 0, the Sound Manager chooses a default size for the buffers.
  869. The third parameter passed to SndStartFilePlay here is set to 0. That parameter is used only when playing sound resources from disk.
  870. The seventh parameter to SndStartFilePlay allows you to specify a routine to be executed when the sound finishes playing. This is useful only for asynchronous play. In Listing 1-2, the value NOT kAsync (that is, FALSE) is passed as the eighth parameter to SndStartFilePlay to request synchronous playback. SndStartFilePlay would return a badChannel result code if you request asynchronous playback because MyPlaySoundFile does not allocate a sound channel.
  871. Checking For Sound-Recording Equipment
  872.  
  873. Before allowing a user to record a sound, you must ensure that sound-recording hardware and software are installed. You can record sound through the microphone built into several Macintosh models, or through third-party sound input devices. Because low-level sound input device drivers handle communication between your application and the sound recording hardware, you do not need to know what type of microphone is available. Listing 1-3 defines a function that determines whether sound recording hardware is available.
  874. Listing 1-3    Determining whether sound recording equipment is available
  875.  
  876. FUNCTION MyHasSoundInput: Boolean;
  877. VAR
  878.     myFeature:                LongInt;
  879.     myErr:                OSErr;
  880. BEGIN
  881.     myErr := Gestalt(gestaltSoundAttr, myFeature);
  882.     IF myErr = noErr THEN                                        {test sound input device bit}
  883.         MyHasSoundInput := BTst(myFeature, gestaltHasSoundInputDevice)
  884.     ELSE
  885.         MyHasSoundInput := FALSE;                                    {no sound features available}
  886. END;
  887. The MyHasSoundInput function defined in Listing 1-3 uses the Gestalt function to determine whether sound input hardware is available and usable on the current Macintosh computer. MyHasSoundInput tests the gestaltHasSoundInputDevice bit and returns TRUE if you can record sounds. MyHasSoundInput returns FALSE if you cannot record sounds (either because no sound input device exists or because the Sound Input Manager is not available).
  888. Note
  889. For more information on the Gestalt function, see Inside Macintosh: Operating System Utilities.u
  890. Recording a Sound Resource
  891.  
  892. You can record sounds from the current input device by using the SndRecord function. The SndRecord function presents the sound recording dialog box. When calling SndRecord, you need to provide a handle to a block of memory where the incoming data should be stored. If you pass the address of a NIL handle, however, the Sound Input Manager allocates a large block of space in your application heap and resizes it when the recording stops. Listing 1-4 illustrates how to call SndRecord.
  893. Listing 1-4    Recording through the sound recording dialog box
  894.  
  895. PROCEDURE MyRecordThruDialog (VAR mySndHandle: Handle);
  896. VAR
  897.     myErr:                OSErr;
  898.     myCorner:                Point;
  899. BEGIN
  900.     MyGetTopLeftCorner(myCorner);
  901.     mySndHandle := NIL;                                {use default memory allocation}
  902.     myErr := SndRecord(NIL, myCorner, siBestQuality, mySndHandle);
  903.     IF (myErr <> noErr) AND (myErr <> userCanceledErr) THEN
  904.         DoError(myErr);
  905. END;
  906. If the user cancels sound recording, then the SndRecord function returns the result code userCanceledErr. The MyRecordThruDialog procedure defined in Listing 1-4 returns a NIL sound handle if the user cancels recording.
  907. If you pass a sound handle that is not NIL as the fourth parameter to the SndRecord function, the Sound Input Manager derives the maximum time of recording from the amount of space reserved by that handle. The handle is resized on completion of the recording.
  908. The first parameter in the call to SndRecord is the address of a filter procedure that determines how user actions in the dialog box are filtered. In Listing 1-4, no filter procedure is desired, so the parameter is specified as NIL. For information on filter procedures, see the chapter “Dialog Manager” in Inside Macintosh: Macintosh Toolbox Essentials.
  909. The second parameter in the call to SndRecord is the desired location (in global coordinates) of the upper-left corner of the dialog box. For example, the Sound control panel displays the dialog box near the control panel. Your application might place the dialog box elsewhere (for example in the standard alert position on the main screen). For more information on centering dialog boxes, see the chapter “Dialog Manager” in Inside Macintosh: Macintosh Toolbox Essentials.
  910. The third parameter in the call to SndRecord specifies the quality of the recording. Currently three values are supported:
  911. CONST
  912.     siBestQuality                        = 'best';                {the best quality available}
  913.     siBetterQuality                        = 'betr';                {a quality better than good}
  914.     siGoodQuality                        = 'good';                {a good quality}
  915. The precise meanings of these constants are defined by the current sound-input device driver. The constant siBestQuality indicates that you want the highest quality recorded sound, usually at the expense of increased storage space (possibly because no compression is performed on the sound data). The constant siGoodQuality indicates that you are willing to sacrifice audio quality if necessary to minimize the amount of storage space required (typically this means that 6:1 compression is performed on the sound data). For most voice recording, you should specify siGoodQuality. The constant siBetterQuality defines a quality and storage space combination that is between those provided by the other two constants.
  916. You could play the sound recorded using the MyRecordThruDialog procedure defined in Listing 1-4 by calling SndPlay and passing it the sound handle mySndHandle. That handle refers to some data in memory that has the structure of an 'snd ' resource, but it is not a handle to an existing resource. To save the recorded data as a resource, you can use the Resource Manager. Listing 1-5 calls the MyRecordThruDialog procedure and then uses the Resource Manager to save the recorded data as a resource in an open resource file.
  917. Listing 1-5    Recording a sound resource
  918.  
  919. PROCEDURE MyRecordSndResource (resFileRefNum: Integer);
  920. CONST
  921.     kMinSysSndRes = 0;                                            {lowest reserved 'snd ' resource ID}
  922.     kMaxSysSndRes = 8191;                                            {highest reserved ID}
  923. VAR
  924.     myPrevResFile:                            Integer;                {current resource file}
  925.     mySndHandle:                            Handle;                {handle to resource data}
  926.     myResID:                            LongInt;                {ID of resource}
  927.     myResName:                            Str255;                {name of resource}
  928.     myErr:                            OSErr;
  929. BEGIN
  930.     myPrevResFile := CurResFile;                                            {remember current resource file}
  931.     UseResFile(resFileRefNum);                                            {temporarily switch resource files}
  932.     MyRecordThruDialog(mySndHandle);                                            {record via standard interface}
  933.     IF mySndHandle <> NIL THEN
  934.     BEGIN                                            {recording finished successfully}
  935.         REPEAT                                        {find acceptable resource ID number}
  936.             myResID := Unique1ID('snd ');
  937.         UNTIL (myResID < kMinSysSndRes) OR (myResID > kMaxSysSndRes);
  938.                                         
  939.         MyGetSoundName(myResName);                                        {get name for sound resource}
  940.                                                 {add resource to file}
  941.         AddResource(mySndHandle, 'snd ', myResID, myResName);
  942.         myErr := ResError;
  943.         IF myErr = noErr THEN
  944.         BEGIN
  945.             UpdateResFile(resFileRefNum);                                            {update resource file}
  946.             myErr := ResError;
  947.         END;
  948.         IF myErr <> noErr THEN 
  949.             DoError(myErr);
  950.     END;
  951.     UseResFile(myPrevResFile);                                            {restore previous resource file}
  952. END;
  953. The MyRecordSndResource procedure defined in Listing 1-5 takes as a parameter the reference number of an open resource file to which you wish to record. The procedure makes that resource file the current resource file and, after recording, reverts to what was previously the active resource file. Note that you should not record to your application’s resource fork, because applications that write to their own resource forks cannot be used by multiple users at once over a network. For more information on reference numbers for resource files, see the chapter “Resource Manager” in Inside Macintosh: More Macintosh Toolbox.
  954. The MyRecordSndResource procedure first presents the sound recording dialog box by calling the MyRecordThruDialog procedure defined in Listing 1-4 on page 1-28. If that procedure returns a valid sound handle, MyRecordSndResource finds an acceptable resource ID for the resource file and then calls a procedure that returns a name for the resource (perhaps by presenting a dialog box that asks the user to name the sound). Finally, MyRecordSndResource adds the resource to the specified resource file and updates that file by calling the Resource Manager procedure UpdateResFile.
  955. Recording a Sound File
  956.  
  957. To record a sound directly into a file, you can call the SndRecordToFile function, which works exactly like SndRecord except that you pass it the file reference number of an open file instead of a handle to some memory. When SndRecordToFile exits successfully, that file contains the recorded audio data in AIFF or AIFF-C format. You can then play the recorded sound by passing that file reference number to the SndStartFilePlay function. (See Listing 1-2 on page 1-26 for a sample function that uses the SndStartFilePlay function.) Listing 1-6 defines a procedure that records a sound into a file using SndRecordToFile.
  958. Listing 1-6    Recording a sound file
  959.  
  960. PROCEDURE MyRecordSoundFile (myFileRefNum: Integer);
  961. VAR
  962.     myErr:                OSErr;
  963.     myCorner:                Point;
  964. BEGIN
  965.     MyGetTopLeftCorner(myCorner);
  966.     myErr := SndRecordToFile(NIL, myCorner, siBestQuality, myFileRefNum);
  967.     IF (myErr <> noErr) AND (myErr <> userCanceledErr) THEN
  968.         DoError(myErr);
  969. END;
  970. The SndRecordToFile function records the sound in the file specified in its fourth parameter. You must open the file before calling the MyRecordSoundFile procedure, and you must close the file after calling it. For more information on creating, opening, and closing files, see the chapter “Introduction to File Management” in Inside Macintosh: Files. 
  971. Checking For Speech Capabilities
  972.  
  973. Because the Speech Manager is not available in all system software versions, your application should always check for speech capabilities before attempting to use them. Listing 1-7 defines a function that determines whether the Speech Manager is available.
  974. Listing 1-7    Checking for speech generation capabilities
  975.  
  976. FUNCTION MyHasSpeech: Boolean;
  977. VAR
  978.     myFeature:                     LongInt;                    {feature being tested}
  979.     myErr:                     OSErr;
  980. BEGIN
  981.     myErr := Gestalt(gestaltSpeechAttr, myFeature);
  982.     IF myErr = noErr THEN                                        {test Speech Manager-present bit}
  983.         MyHasSpeech := BTst(myFeature, gestaltSpeechMgrPresent)
  984.     ELSE
  985.         MyHasSpeech := FALSE;                                    {no speech features available}
  986. END;
  987. The MyHasSpeech function defined in Listing 1-7 uses the Gestalt function to determine whether the Speech Manager is available. The MyHasSpeech function tests the gestaltSpeechMgrPresent bit and returns TRUE if and only if the Speech Manager is present. If the Gestalt function cannot obtain the desired information and returns a result code other than noErr, the MyHasSpeech function assumes that the Speech Manager is not available and therefore returns FALSE.
  988. Generating Speech From a String
  989.  
  990. It is easy to have the Speech Manager generate speech from a string stored as a variable of type Str255. The SpeakString function takes one parameter, the string to be spoken. SpeakString automatically allocates a speech channel, uses that channel to produce speech, and then disposes of the speech channel when speaking is complete. Speech generation is asynchronous, but because SpeakString copies the string you pass it into an internal buffer, you are free to release the memory you allocated for the string as soon as SpeakString returns.
  991. Listing 1-8 show how you can use the SpeakString function to convert a string stored in a resource of type 'STR#' into speech.
  992. Listing 1-8    Using SpeakString to generate speech from a string
  993.  
  994. PROCEDURE MySpeakStringResource (myStrListID: Integer; myIndex: Integer);
  995. VAR
  996.     myString:                    Str255;                                                {the string to speak}
  997.     myErr:                    OSErr;
  998. BEGIN
  999.     GetIndString(myString, myStrListID, myIndex);                                                                    {load the string}
  1000.     myErr := SpeakString(myString);                                                                    {start speaking}
  1001.     IF myErr <> noErr THEN
  1002.         DoError(myErr);
  1003. END;
  1004. The MySpeakStringResource procedure defined in Listing 1-8 takes as parameters the resource ID of the 'STR#' resource containing the string and the index of the string within that resource. MySpeakStringResource passes these values to the GetIndString procedure, which loads the string from the resource file into memory. MySpeakStringResource then calls the SpeakString function to convert the string into speech; if an error occurs, it calls an application-defined error-handling procedure.
  1005. The speech that the SpeakString function generates is asynchronous; that is, control returns to your application before the function finishes speaking the string. If you would like to generate speech synchronously, you can use SpeakString in conjunction with the SpeechBusy function, which returns the number of active speech channels, including the speech channel created by the SpeakString function. 
  1006. Listing 1-9 illustrates how you can use SpeechBusy and SpeakString to generate speech synchronously.
  1007. Listing 1-9    Generating speech synchronously
  1008.  
  1009. PROCEDURE MySpeakStringResourceSync (myStrListID: Integer; myIndex: Integer);
  1010. VAR
  1011.     activeChannels:                         Integer;                        {number of active speech channels}
  1012. BEGIN
  1013.     activeChannels := SpeechBusy;                                                {find number of active channels}
  1014.     MySpeakStringResource(myStrListID, myIndex);                                                                    {speak the string}
  1015.  
  1016.     {Wait until channel is no longer processing speech.}
  1017.     REPEAT
  1018.     UNTIL SpeechBusy = activeChannels;
  1019. END;
  1020. The MySpeakStringResourceSync procedure defined in Listing 1-9 uses the MySpeakStringResource procedure defined in Listing 1-8 to speak a string. However, before calling MySpeakStringResource, MySpeakStringResourceSync calls the SpeechBusy function to determine how many speech channels are active. After the speech has begun, the MySpeakStringResourceSync function does not return until the number of speech channels active again falls to this level.
  1021. Note
  1022. Ordinarily, you should play speech asynchronously, to allow the user to perform other activities while speech is being generated. You might play speech synchronously if other activities performed by your application should not occur while speech is being generated.u
  1023. You can use the SpeakString function to stop speech being generated by a prior call to SpeakString. You might do this, for example, if the user switches to another application or closes a document associated with speech being generated. To stop speech, simply pass a zero-length string to the SpeakString function (or if you are programming in C, pass NULL).
  1024. Listing 1-10 shows how your application can stop speech generated by a call to the SpeakString function.
  1025. Listing 1-10    Stopping speech generated by SpeakString
  1026.  
  1027. PROCEDURE MyStopSpeech;
  1028. VAR
  1029.     myString:                    Str255;                        {an empty string}
  1030.     myErr:                    OSErr;
  1031. BEGIN
  1032.     myString[0] := Char(0);                                            {set length of string to 0}
  1033.     myErr := SpeakString(myString);                                            {stop previous speech}
  1034.     IF myErr <> noErr THEN
  1035.         DoError(myErr);
  1036. END;
  1037. The MyStopSpeech procedure defined in Listing 1-10 sets the length byte of a string to 0 before calling the SpeakString function. To execute this code in some development systems, you need to ensure that range checking is disabled. Consult your development system’s documentation for details on enabling and disabling range checking.
  1038.  
  1039. Sound Reference
  1040.  
  1041. This section describes the routines used in this chapter to illustrate basic sound producing and recording operations. These are high-level routines that you can use to play and record sound resources and sound files, and to convert text to speech. The routines described in this section also appear in the appropriate reference sections of the other chapters in this book.
  1042. For a description of sound-related data structures and other sound-related routines, see the chapters “Sound Manager,” “Sound Input Manager,” and “Speech Manager” in this book. For a detailed description of the formats of sound resources and sound files, see the chapter “Sound Manager” in this book.
  1043. Routines
  1044.  
  1045. This section describes the high-level system software routines that you can use to play and record sound resources and sound files, or to convert a text string to spoken words. These routines belong to the Sound Manager.
  1046. Playing Sounds
  1047.  
  1048. You can use the SysBeep procedure to play the system alert sound, the SndPlay function to play the sound stored in any 'snd ' resource, and the SndStartFilePlay function to play a sound file.
  1049. SysBeep
  1050.  
  1051. You can use the SysBeep procedure to play the system alert sound.
  1052. PROCEDURE SysBeep (duration: Integer);
  1053. duration    The duration (in ticks) of the resulting sound. This parameter is ignored except on a Macintosh Plus, Macintosh SE, or Macintosh Classic when the system alert sound is the Simple Beep. The recommended duration is 30 ticks, which equals one-half second.
  1054. DESCRIPTION
  1055. The SysBeep procedure causes the Sound Manager to play the system alert sound at its current volume. If necessary, the Sound Manager loads into memory the sound resource containing the system alert sound and links it to a sound channel. The user selects a system alert sound in the Alert Sounds subpanel of the Sound control panel.
  1056. The volume of the sound produced depends on the current setting of the system alert sound volume, which the user can adjust in the Alert Sounds subpanel of the Sound control panel. The system alert sound volume can also be read and set by calling the GetSysBeepVolume and SetSysBeepVolume routines. If the volume is set to 0 (silent) and the system alert sound is enabled, calling SysBeep causes the menu bar to blink once.
  1057. SPECIAL CONSIDERATIONS
  1058. Because the SysBeep procedure moves memory, you should not call it at interrupt time.
  1059. SEE ALSO
  1060. For information on enabling and disabling the system alert sound or for information on reading and adjusting the system alert sound volume, see the chapter “Sound Manager” in this book.
  1061. SndPlay
  1062.  
  1063. You can use the SndPlay function to play a sound resource that your application has loaded into memory.
  1064. FUNCTION SndPlay (chan: SndChannelPtr; sndHdl: Handle; 
  1065.                         async: Boolean): OSErr;
  1066. chan    A pointer to a valid sound channel. You can pass NIL instead of a pointer to a sound channel if you want the Sound Manager to internally allocate a sound channel in your application’s heap zone.
  1067. sndHdl    A handle to the sound resource to play.
  1068. async    A Boolean value that indicates whether the sound should be played asynchronously (TRUE) or synchronously (FALSE). This parameter is ignored (and the sound plays synchronously) if NIL is passed in the first parameter.
  1069. DESCRIPTION
  1070. The SndPlay function attempts to play the sound located at sndHdl, which is expected to have the structure of a format 1 'snd ' resource. If the resource has not yet been loaded, the SndPlay function fails and returns the resProblem result code. The handle you pass in the sndHdl parameter must be locked for as long as the sound is playing asynchronously.
  1071. The chan parameter is a pointer to a sound channel. If chan is not NIL, it is used as a valid channel. If chan is NIL, an internally allocated sound channel is used. Commands and data contained in the sound handle are then sent to the channel. Note that you can pass SndPlay a handle to some data created by calling the Sound Input Manager’s SndRecord function as well as a handle to an actual 'snd ' resource that you have loaded into memory.
  1072. SPECIAL CONSIDERATIONS
  1073. Because the SndPlay function moves memory, you should not call it at interrupt time.
  1074. RESULT CODESnoErr    0    No error    
  1075. notEnoughHardwareErr    –201    Insufficient hardware available    
  1076. resProblem    –204    Problem loading the resource    
  1077. badChannel    –205    Channel is corrupt or unusable    
  1078. badFormat    –206    Resource is corrupt or unusable    
  1079.  
  1080. SEE ALSO
  1081. For an example of how to play a sound resource using the SndPlay function, see “Playing a Sound Resource” on page 1-25. For more information on the SndPlay function, see the chapter “Sound Manager” in this book.
  1082. SndStartFilePlay
  1083.  
  1084. You can call the SndStartFilePlay function to initiate a play from disk.
  1085. FUNCTION SndStartFilePlay (chan: SndChannelPtr; fRefNum: Integer;
  1086.                                      resNum: Integer; bufferSize: LongInt;
  1087.                                      theBuffer: Ptr; 
  1088.                                     theSelection: AudioSelectionPtr; 
  1089.                                     theCompletion: ProcPtr; 
  1090.                                     async: Boolean): OSErr;
  1091. chan    A pointer to a valid sound channel. You can pass NIL instead of a pointer to a sound channel if you want the Sound Manager to internally allocate a sound channel in your application’s heap zone.
  1092. fRefNum    The file reference number of the AIFF or AIFF-C file to play. To play a sound resource rather than a sound file, this field should be 0.
  1093. resNum    The resource ID number of a sound resource to play. To play a sound file rather than a sound resource, this field should be 0.
  1094. bufferSize
  1095. The number of bytes of memory that the Sound Manager is to use for input buffering while reading in sound data. For SndStartFilePlay to execute successfully on the slowest Macintosh computers, use a buffer of at least 20,480 bytes. You can pass the value 0 to instruct the Sound Manager to allocate a buffer of the default size.
  1096. theBuffer    A pointer to a buffer that the Sound Manager should use for input buffering while reading in sound data. If this parameter is NIL, the Sound Manager allocates two buffers, each half the size of the value specified in the bufferSize parameter. If this parameter is not NIL, the buffer should be a nonrelocatable block of size bufferSize.
  1097. theSelection
  1098. A pointer to an audio selection record that specifies which portion of a sound should be played. You can pass NIL to specify that the Sound Manager should play the entire sound.
  1099. theCompletion
  1100. A pointer to a completion routine that the Sound Manager calls when the sound is finished playing. You can pass NIL to specify that the Sound Manager should not execute a completion routine. This field is useful only for asynchronous play.
  1101. async    A Boolean value that indicates whether the sound should be played asynchronously (TRUE) or synchronously (FALSE). You can play sound asynchronously only if you allocate your own sound channel (using SndNewChannel). If you pass NIL in the chan parameter and TRUE for this parameter, the SndStartFilePlay function returns the badChannel result code.
  1102. DESCRIPTION
  1103. The SndStartFilePlay function begins a continuous play from disk on a sound channel. The chan parameter is a pointer to the sound channel. If chan is not NIL, it is used as a valid channel. If chan is NIL, an internally allocated sound channel is used for play from disk. This internally allocated sound channel is not passed back to you. Because SndPauseFilePlay and SndStopFilePlay (described in the chapter “Sound Manager”) require a sound-channel pointer, you must allocate your own channel if you wish to use those routines.
  1104. The sounds you wish to play can be stored either in a file or in an 'snd ' resource. If you are playing a file, then fRefNum should be the file reference number of the file to be played and the parameter resNum should be set to 0. If you are playing an 'snd ' resource, then fRefNum should be set to 0 and resNum should be the resource ID number (not the file reference number) of the resource to play.
  1105. SPECIAL CONSIDERATIONS
  1106. Because the SndStartFilePlay function moves memory, you should not call it at interrupt time.
  1107. ASSEMBLY-LANGUAGE INFORMATION
  1108. The trap macro and routine selector for the SndStartFilePlay function are
  1109. Trap macro    Selector    
  1110. _SoundDispatch    $0D000008    
  1111.  
  1112. RESULT CODESnoErr    0    No error    
  1113. notEnoughHardwareErr    –201    Insufficient hardware available    
  1114. queueFull    –203    No room in the queue    
  1115. resProblem    –204    Problem loading the resource    
  1116. badChannel    –205    Channel is corrupt or unusable    
  1117. badFormat    –206    Resource is corrupt or unusable    
  1118. notEnoughBufferSpace    –207    Insufficient memory available    
  1119. badFileFormat    –208    File is corrupt or unusable, or not AIFF or AIFF-C    
  1120. channelBusy    –209    Channel is busy    
  1121. buffersTooSmall    –210    Buffer is too small    
  1122. siInvalidCompression    –223    Invalid compression type    
  1123.  
  1124. SEE ALSO
  1125. For an example of how to play a sound file using the SndStartFilePlay function, see “Playing a Sound File” on page 1-26. For information on completion routines, see the chapter “Sound Manager” in this book.
  1126. Recording Sounds
  1127.  
  1128. The Sound Input Manager provides two high-level sound input routines, SndRecord and SndRecordToFile, for recording sound. These input routines are analogous to the two Sound Manager functions SndPlay and SndStartFilePlay. By using these high-level routines, you can be assured that your application presents a user interface that is consistent with that displayed by other applications recording sounds. Both SndRecord and SndRecordToFile attempt to record sound data from the sound input hardware currently selected in the Sound In control panel.
  1129. SndRecord
  1130.  
  1131. You can use the SndRecord function to record sound resources into memory.
  1132. FUNCTION SndRecord (filterProc: ProcPtr; corner: Point; 
  1133.                             quality: OSType; VAR sndHandle: Handle): 
  1134.                             OSErr;
  1135. filterProc
  1136. A pointer to an event filter function that determines how user actions in the sound recording dialog box are filtered (similar to the filterProc parameter specified in a call to the ModalDialog procedure). By specifying your own filter function, you can override or add to the default actions of the items in the dialog box. If filterProc isn’t NIL, SndRecord filters events by calling the function that filterProc points to.
  1137. corner    The horizontal and vertical coordinates of the upper-left corner of the sound recording dialog box (in global coordinates).
  1138. quality    The desired quality of the recorded sound.
  1139. sndHandle    On entry, a handle to some storage space or NIL. On exit, a handle to a valid sound resource (or unchanged, if the call did not execute successfully).
  1140. DESCRIPTION
  1141. The SndRecord function records sound into memory. The recorded data has the structure of a format 1 'snd ' resource and can later be played using the SndPlay function or can be stored as a resource. SndRecord displays a sound recording dialog box and is always called synchronously. Controls in the dialog box allow the user to start, stop, pause, and resume sound recording, as well as to play back the recorded sound. The dialog box also lists the remaining recording time and the current microphone sound level.
  1142. The quality parameter defines the desired quality of the recorded sound. Currently, three values are recognized for the quality parameter:
  1143. CONST
  1144.     siBestQuality                            = 'best';                {the best quality available}
  1145.     siBetterQuality                            = 'betr';                {a quality better than good}
  1146.     siGoodQuality                            = 'good';                {a good quality}
  1147. The precise meanings of these parameters are defined by the sound input device driver. For Apple-supplied drivers, this parameter determines whether the recorded sound is to be compressed, and if so, whether at a 6:1 or a 3:1 ratio. The quality siBestQuality does not compress the sound and provides the best quality output, but at the expense of increased memory use. The quality siBetterQuality is suitable for most nonvoice recording, and siGoodQuality is suitable for voice recording.
  1148. The sndHandle parameter is a handle to some storage space. If the handle is NIL, the Sound Input Manager allocates a handle of the largest amount of space that it can find in your application’s heap and returns this handle in the sndHandle parameter. The Sound Input Manager resizes the handle when the user clicks the Save button in the sound recording dialog box. If the sndHandle parameter passed to SndRecord is not NIL, the Sound Input Manager simply stores the recorded data in the location specified by that handle.
  1149. SPECIAL CONSIDERATIONS
  1150. Because the SndRecord function moves memory, you should not call it at interrupt time.
  1151. ASSEMBLY-LANGUAGE INFORMATION
  1152. The trap macro and routine selector for the SndRecord function are
  1153. Trap macro    Selector    
  1154. _SoundDispatch    $08040014    
  1155.  
  1156. RESULT CODESnoErr    0    No error    
  1157. userCanceledErr    –128    User canceled the operation    
  1158. siBadSoundInDevice    –221    Invalid sound input device    
  1159. siUnknownQuality    –232    Unknown quality    
  1160.  
  1161. SEE ALSO
  1162. For an example of how to record a sound resource using the SndRecord function, see “Recording a Sound Resource” on page 1-28. See the chapter “Dialog Manager” in Inside Macintosh: Macintosh Toolbox Essentials for a complete description of event filter functions.
  1163. SndRecordToFile
  1164.  
  1165. You can use SndRecordToFile to record sound data into a file. 
  1166. FUNCTION SndRecordToFile (filterProc: ProcPtr; corner: Point; 
  1167.                                     quality: OSType; 
  1168.                                     fRefNum: Integer): OSErr;
  1169. filterProc
  1170. A pointer to a function that determines how user actions in the sound recording dialog box are filtered.
  1171. corner    The horizontal and vertical coordinates of the upper-left corner of the sound recording dialog box (in global coordinates).
  1172. quality    The desired quality of the recorded sound. The values you can use for this parameter are described on page 1-39.
  1173. fRefNum    The file reference number of an open file to save the audio data in.
  1174. DESCRIPTION
  1175. The SndRecordToFile function works just like SndRecord except that it stores the sound input data into a file. The resulting file is in either AIFF or AIFF-C format and contains the information necessary to play the file by using the Sound Manager’s SndStartFilePlay function. The SndRecordToFile function is always called synchronously.
  1176. Your application must open the file specified in the fRefNum parameter before calling the SndRecordToFile function. Your application must close the file sometime after calling SndRecordToFile.
  1177. SPECIAL CONSIDERATIONS
  1178. Because the SndRecordToFile function moves memory, you should not call it at interrupt time.
  1179. ASSEMBLY-LANGUAGE INFORMATION
  1180. The trap macro and routine selector for the SndRecordToFile function are
  1181. Trap macro    Selector    
  1182. _SoundDispatch    $07080014    
  1183.  
  1184. RESULT CODESnoErr    0    No error    
  1185. userCanceledErr    –128    User canceled the operation    
  1186. siBadSoundInDevice    –221    Invalid sound input device    
  1187. siUnknownQuality    –232    Unknown quality    
  1188.  
  1189. SEE ALSO
  1190. For an example of how to record a sound file using the SndRecordToFile function, see “Recording a Sound File” on page 1-31. See the chapter “Dialog Manager” in Inside Macintosh: Macintosh Toolbox Essentials for a complete description of event filter functions.
  1191. Generating and Stopping Speech
  1192.  
  1193. Your application can use the SpeakString function to generate speech or stop speech currently being generated by SpeakString. By calling the SpeechBusy function before and after a call to SpeakString, your application can determine when speaking is complete. These routines belong to the Speech Manager.
  1194. SpeakString
  1195.  
  1196. You can use the SpeakString function to have the Speech Manager read a text string.
  1197. FUNCTION SpeakString (s: Str255): OSErr;
  1198. s    The string to be spoken.
  1199. DESCRIPTION
  1200. The SpeakString function attempts to speak the Pascal-style text string contained in the string s. Speech is produced asynchronously using the default system voice. When an application calls this function, the Speech Manager makes a copy of the passed string and creates any structures required to speak it. As soon as speaking has begun, control is returned to the application. The synthesized speech is generated asynchronously to the application so that normal processing can continue while the text is being spoken. No further interaction with the Speech Manager is required at this point, and the application is free to release the memory that the original string occupied.
  1201. If SpeakString is called while a prior string is still being spoken, the sound currently being synthesized is interrupted immediately. Conversion of the new text into speech is then begun. If you pass a zero-length string (or, in C, a null pointer) to SpeakString, the Speech Manager stops any speech previously being synthesized by SpeakString without generating additional speech. If your application uses SpeakString, it is often a good idea to stop any speech in progress whenever your application receives a suspend event. (Note, however, that calling SpeakString with a zero-length string has no effect on speech channels other than the one managed internally by the Speech Manager for the SpeakString function.)
  1202. The text passed to the SpeakString function may contain embedded speech commands, which are described in the chapter “Speech Manager” in this book.
  1203. SPECIAL CONSIDERATIONS
  1204. Because the SpeakString function moves memory, you should not call it at interrupt time.
  1205. ASSEMBLY-LANGUAGE INFORMATION
  1206. The trap macro and routine selector for the SpeakString function are
  1207. Trap macro    Selector    
  1208. _SoundDispatch    $0220000C    
  1209.  
  1210. RESULT CODESnoErr    0    No error    
  1211. memFullErr    –108    Not enough memory to speak    
  1212. synthOpenFailed    –241    Could not open another speech synthesizer channel    
  1213.  
  1214. SEE ALSO
  1215. For an example of how to read a text string using the SpeakString function, see “Generating Speech From a String” on page 1-32. See the chapter “Dialog Manager” in Inside Macintosh: Macintosh Toolbox Essentials for a complete description of event filter functions.
  1216. SpeechBusy
  1217.  
  1218. You can use the SpeechBusy function to determine whether any channels of speech are currently synthesizing speech.
  1219. FUNCTION SpeechBusy: Integer;
  1220. DESCRIPTION
  1221. The SpeechBusy function returns the number of speech channels that are currently synthesizing speech in the application. This is useful when you want to ensure that an earlier speech request has been completed before having the system speak again. Note that paused speech channels are counted among those that are synthesizing speech.
  1222. The speech channel that the Speech Manager allocates internally in response to calls to the SpeakString function is counted in the number returned by SpeechBusy. Thus, if you use just SpeakString to initiate speech, SpeechBusy always returns 1 as long as speech is being produced. When SpeechBusy returns 0, all initiated speech has finished.
  1223. SPECIAL CONSIDERATIONS
  1224. You can call the SpeechBusy function at interrupt time.
  1225. ASSEMBLY-LANGUAGE INFORMATION
  1226. The trap macro and routine selector for the SpeechBusy function are
  1227. Trap macro    Selector    
  1228. _SoundDispatch    $003C000C    
  1229.  
  1230.  
  1231.  
  1232. Summary of Sound
  1233.  
  1234. Pascal Summary
  1235.  
  1236. Constants
  1237.  
  1238. CONST
  1239.     {Gestalt sound attributes selector and response bits}
  1240.     gestaltSoundAttr                                    = 'snd ';            {sound attributes selector}
  1241.     gestaltStereoCapability                                    = 0;            {built-in hw can play stereo sounds}
  1242.     gestaltStereoMixing                                    = 1;            {built-in hw mixes stereo to mono}
  1243.     gestaltSoundIOMgrPresent                                    = 3;            {sound input routines available}
  1244.     gestaltBuiltInSoundInput                                    = 4;            {built-in input hw available}
  1245.     gestaltHasSoundInputDevice                                    = 5;            {sound input device available}
  1246.     gestaltPlayAndRecord                                    = 6;            {built-in hw can play while recording}
  1247.     gestalt16BitSoundIO                                     = 7;            {built-in hw can handle 16-bit data}
  1248.     gestaltStereoInput                                     = 8;            {built-in hw can record stereo sounds}
  1249.     gestaltLineLevelInput                                     = 9;            {built-in input hw needs line level}
  1250.     gestaltSndPlayDoubleBuffer                                    = 10;            {play from disk routines available}
  1251.     gestaltMultiChannels                                    = 11;            {multiple channels of sound supported}
  1252.     gestalt16BitAudioSupport                                     = 12;            {16-bit audio data supported}
  1253.     {Gestalt selector and response bits for speech attributes}
  1254.     gestaltSpeechAttr                                    = 'ttsc';            {speech attributes selector}
  1255.     gestaltSpeechMgrPresent                                    = 0;            {Speech Manager is present}
  1256.     {recording qualities}
  1257.     siBestQuality                                = 'best';                {the best quality available}
  1258.     siBetterQuality                                = 'betr';                {a quality better than good}
  1259.     siGoodQuality                                = 'good';                {a good quality}
  1260. Routines
  1261.  
  1262. Playing Sounds
  1263. PROCEDURE SysBeep    (duration: Integer);
  1264. FUNCTION SndPlay    (chan: SndChannelPtr; sndHdl: Handle; 
  1265. async: Boolean): OSErr;
  1266. FUNCTION SndStartFilePlay    (chan: SndChannelPtr; fRefNum: Integer; 
  1267. resNum: Integer; bufferSize: LongInt; theBuffer: Ptr; 
  1268. theSelection: AudioSelectionPtr; theCompletion: ProcPtr; async: Boolean): OSErr;
  1269. Recording Sounds
  1270. FUNCTION SndRecord    (filterProc: ProcPtr; corner: Point; 
  1271. quality: OSType; VAR sndHandle: Handle): OSErr;
  1272. FUNCTION SndRecordToFile    (filterProc: ProcPtr; corner: Point;
  1273. quality: OSType; fRefNum: Integer): OSErr;
  1274. Generating and Stopping Speech
  1275. FUNCTION SpeakString    (s: Str255): OSErr;
  1276. FUNCTION SpeechBusy    : Integer;
  1277. C Summary
  1278.  
  1279. Constants
  1280.  
  1281. /*Gestalt sound attributes selector and response bits*/
  1282. #define gestaltSoundAttr                                     'snd '            /*sound attributes selector*/
  1283. enum {
  1284.     gestaltStereoCapability                                    = 0,        /*built-in hw can play stereo sounds*/
  1285.     gestaltStereoMixing                                    = 1,        /*built-in hw mixes stereo to mono*/
  1286.     gestaltSoundIOMgrPresent                                    = 3,        /*sound input routines available*/
  1287.     gestaltBuiltInSoundInput                                    = 4,        /*built-in input hw available*/
  1288.     gestaltHasSoundInputDevice                                    = 5,        /*sound input device available*/
  1289.     gestaltPlayAndRecord                                    = 6,        /*built-in hw can play while recording*/
  1290.     gestalt16BitSoundIO                                     = 7,        /*built-in hw can handle 16-bit data*/
  1291.     gestaltStereoInput                                     = 8,        /*built-in hw can record stereo sounds*/
  1292.     gestaltLineLevelInput                                     = 9,        /*built-in input hw needs line level*/
  1293.     gestaltSndPlayDoubleBuffer                                    = 10,        /*play from disk routines available*/
  1294.     gestaltMultiChannels                                    = 11,        /*multiple channels of sound supported*/
  1295.     gestalt16BitAudioSupport                                     = 12        /*16-bit audio data supported*/
  1296. };
  1297. /*Gestalt selector and response bits for speech attributes*/
  1298. #define gestaltSpeechAttr                                    'ttsc'            /*speech attributes selector*/
  1299. enum {
  1300.     gestaltSpeechMgrPresent                                    = 0        /*Speech Manager is present*/
  1301. };
  1302. /*recording qualities*/
  1303. #define siBestQuality                                        'best'            /*the best quality available*/
  1304. #define siBetterQuality                                        'betr'            /*a quality better than good*/
  1305. #define siGoodQuality                                        'good'            /*a good quality*/
  1306. Routines
  1307.  
  1308. Playing Sounds
  1309. pascal void SysBeep    (short duration);
  1310. pascal OSErr SndPlay    (SndChannelPtr chan, Handle sndHdl, 
  1311. Boolean async);
  1312. pascal OSErr SndStartFilePlay
  1313. (SndChannelPtr chan, short fRefNum,
  1314. short resNum, long bufferSize, void *theBuffer,
  1315. AudioSelectionPtr theSelection,
  1316. FilePlayCompletionProcPtr theCompletion, Boolean async);
  1317. Recording Sounds
  1318. pascal OSErr SndRecord    (ModalFilterProcPtr filterProc, Point corner,
  1319. OSType quality, Handle *sndHandle);
  1320. pascal OSErr SndRecordToFile
  1321. (ModalFilterProcPtr filterProc, Point corner,
  1322. OSType quality, short fRefNum);
  1323. Generating and Stopping Speech
  1324. pascal OSErr SpeakString    (StringPtr s);
  1325. pascal short SpeechBusy    (void);
  1326. Result CodesnoErr    0    No error    
  1327. userCanceledErr    –128    User canceled the operation    
  1328. noHardwareErr    –200    Required sound hardware not available    
  1329. notEnoughHardwareErr    –201    Insufficient hardware available    
  1330. queueFull    –203    No room in the queue    
  1331. resProblem    –204    Problem loading the resource    
  1332. badChannel    –205    Channel is corrupt or unusable    
  1333. badFormat    –206    Resource is corrupt or unusable    
  1334. notEnoughBufferSpace    –207    Insufficient memory available    
  1335. badFileFormat    –208    File is corrupt or unusable, or not AIFF or AIFF-C    
  1336. channelBusy    –209    Channel is busy    
  1337. buffersTooSmall    –210    Buffer is too small    
  1338. siBadSoundInDevice    –221    Invalid sound input device    
  1339. siInvalidCompression    –223    Invalid compression type    
  1340. siUnknownQuality    –232    Unknown quality    
  1341. synthOpenFailed    –241    Could not open another speech synthesizer channel    
  1342.  
  1343.  
  1344.  
  1345. Listing 2-0
  1346. Table 2-0
  1347. Sound Manager
  1348. Contents
  1349. About the Sound Manager2-6
  1350. Sound Data2-7
  1351. Square-Wave Data2-7
  1352. Wave-Table Data2-8
  1353. Sampled-Sound Data2-9
  1354. Sound Commands2-11
  1355. Sound Channels2-13
  1356. Sound Compression and Expansion2-14
  1357. Using the Sound Manager2-17
  1358. Managing Sound Channels2-19
  1359. Allocating Sound Channels2-20
  1360. Initializing Sound Channels2-22
  1361. Releasing Sound Channels2-24
  1362. Manipulating a Sound That Is Playing2-25
  1363. Stopping Sound Channels2-28
  1364. Pausing and Restarting Sound Channels2-29
  1365. Synchronizing Sound Channels2-30
  1366. Managing Sound Volumes2-31
  1367. Obtaining Sound-Related Information2-32
  1368. Obtaining Information About Available Sound Features2-33
  1369. Obtaining Version Information2-34
  1370. Testing for Multichannel Sound and Play-From-Disk Capabilities2-35
  1371. Obtaining Information About a Single Sound Channel2-37
  1372. Obtaining Information About All Sound Channels2-39
  1373. Determining and Changing the Status of the System Alert Sound2-40
  1374. Playing Notes2-41
  1375. Installing Voices Into Channels  2-43
  1376. Looping a Sound Indefinitely2-45
  1377. Playing Sounds Asynchronously 2-46
  1378. Using Callback Procedures2-47
  1379. Synchronizing Sound With Other Actions2-51
  1380. Managing an Asynchronous Play From Disk2-52
  1381. Playing Selections2-53
  1382. Managing Multiple Sound Channels2-53
  1383. Parsing Sound Resources and Sound Files2-56
  1384. Obtaining a Pointer to a Sound Header2-57
  1385. Playing Sounds Using Low-Level Routines2-61
  1386. Finding a Chunk in a Sound File2-62
  1387. Compressing and Expanding Sounds2-66
  1388. Using Double Buffers2-68
  1389. Setting Up Double Buffers2-70
  1390. Writing a Doubleback Procedure2-72
  1391. Sound Storage Formats2-73
  1392. Sound Resources2-74
  1393. The Format 1 Sound Resource2-75
  1394. The Format 2 Sound Resource 2-80
  1395. Sound Files2-81
  1396. Chunk Organization and Data Types2-82
  1397. The Form Chunk2-83
  1398. The Format Version Chunk2-84
  1399. The Common Chunk2-85
  1400. The Sound Data Chunk2-87
  1401. Format of Entire Sound Files2-87
  1402. Sound Manager Reference2-89
  1403. Constants2-89
  1404. Gestalt Selector and Response Bits2-90
  1405. Channel Initialization Parameters2-91
  1406. Sound Command Numbers2-92
  1407. Chunk IDs2-98
  1408. Data Structures2-99
  1409. Sound Command Records2-99
  1410. Audio Selection Records2-100
  1411. Sound Channel Status Records2-101
  1412. Sound Manager Status Records2-102
  1413. Sound Channel Records2-103
  1414. Sound Header Records2-104
  1415. Extended Sound Header Records2-106
  1416. Compressed Sound Header Records2-108
  1417. Sound Double Buffer Header Records2-111
  1418. Sound Double Buffer Records2-112
  1419. Chunk Headers2-113
  1420. Form Chunks2-113
  1421. Format Version Chunks2-114
  1422. Common Chunks2-115
  1423. Extended Common Chunks2-115
  1424. Sound Data Chunks 2-117
  1425. Version Records2-118
  1426. Leftover Blocks2-119
  1427. State Blocks2-119
  1428. Sound Manager Routines2-119
  1429. Playing Sound Resources2-120
  1430. Playing From Disk2-123
  1431. Allocating and Releasing Sound Channels2-127
  1432. Sending Commands to a Sound Channel2-130
  1433. Obtaining Information2-132
  1434. Controlling Volume Levels2-139
  1435. Compressing and Expanding Audio Data2-142
  1436. Managing Double Buffers2-147
  1437. Performing Unsigned Fixed-Point Arithmetic2-148
  1438. Linking Modifiers to Sound Channels2-149
  1439. Application-Defined Routines2-151
  1440. Completion Routines2-151
  1441. Callback Procedures 2-152
  1442. Doubleback Procedures2-153
  1443. Resources2-154
  1444. The Sound Resource2-154
  1445. Summary of the Sound Manager2-157
  1446. Pascal Summary2-157
  1447. Constants2-157
  1448. Data Types2-161
  1449. Sound Manager Routines2-168
  1450. Application-Defined Routines2-170
  1451. C Summary2-170
  1452. Constants2-170
  1453. Data Types2-175
  1454. Sound Manager Routines2-182
  1455. Application-Defined Routines2-184
  1456. Assembly-Language Summary2-184
  1457. Data Structures2-184
  1458. Trap Macros2-188
  1459. Result Codes2-188
  1460. Sound Manager
  1461. This chapter describes the Sound Manager, the part of the Macintosh system software that controls the production and manipulation of sounds on Macintosh computers. You can use the Sound Manager to create a wide variety of sounds and to manipulate sounds in many ways. The Sound Manager is also used by other parts of the Macintosh system software that produce sounds, such as the Speech Manager and QuickTime.
  1462. To use this chapter, you should already be familiar with the information in the chapter “Introduction to Sound on the Macintosh” earlier in this book, especially with the portions of that chapter that describe the Macintosh sound architecture and the routines related to sound output. That chapter shows how your application can play a sound resource or a sound file synchronously (that is, with other processing suspended while the sound plays).
  1463. You should read this chapter if you need a greater degree of control over sound output than the routines described in that introductory chapter provide. For example, if you want to play sounds asynchronously or to exercise very fine control over the process of sound production, this chapter contains information you need.
  1464. This chapter begins by describing the capabilities of the Sound Manager and the role of sound commands and sound channels in producing sound. Then it explains how you can use the Sound Manager to
  1465. n    create and manage sound channels
  1466. n    obtain information about available sound features and sound channels
  1467. n    play notes and other sounds at various frequencies and volumes
  1468. n    play one or more sounds asynchronously
  1469. n    parse sound resources and sound files to obtain information about them
  1470. n    compress and expand sound data
  1471. n    use double buffers to bypass the normal play-from-disk routines
  1472. You’re not likely to use all of these capabilities in a single application. In general, you should read the section “About the Sound Manager” and then turn to the parts of the section “Using the Sound Manager” that describe the features you want to use in your application. The section “Sound Storage Formats” beginning on page 2-73 explains in detail the format of sound resources and sound files. You can find a complete reference to the Sound Manager data structures and routines in the section “Sound Manager Reference” beginning on page 2-89.
  1473. IMPORTANT
  1474. This chapter describes the capabilities and programming interfaces of version 3.0 of the Sound Manager. See the chapter “Introduction to Sound on the Macintosh” for some information on how version 3.0 differs from earlier versions. The capabilities and performance of version 3.0 are significantly better than those of all previous Sound Manager versions, even though their programming interfaces are largely identical. This chapter occasionally warns you about techniques or routines that cannot be used in versions prior to 3.0, but it does not provide an exhaustive comparison of all available versions.s
  1475.  
  1476.  
  1477. About the Sound Manager
  1478.  
  1479. The Sound Manager is a collection of routines that your application can use to create sound without a knowledge of or dependence on the actual sound-producing hardware available on any particular Macintosh computer. More generally, the Sound Manager is responsible for managing all sound production on Macintosh computers. Other parts of the Macintosh system software that need to create or modify sounds use the Sound Manager to do so. Figure 2-1 shows the position of the Sound Manager in relation to sound-producing applications and to other parts of the system software, such as the Speech Manager and QuickTime.
  1480. Figure 2-1    The position of the Sound Manager
  1481.  
  1482. The Sound Manager was first introduced in system software version 6.0 and has been significantly enhanced since that time. Prior to system software version 6.0, applications could create sounds using the Sound Driver.
  1483. IMPORTANT
  1484. IMPORTANT
  1485. To ensure compatibility across all models of Macintosh computers, you should always use the Sound Manager rather than the Sound Driver, which is no longer documented or supported by Apple Computer, Inc. The Sound Manager is simpler and much more powerful than the Sound Driver. Moreover, Sound Driver code might not work on some Macintosh computers.s
  1486. This section describes the three basic ways of defining sounds, namely using wave-table data, square-wave data, or sampled-sound data. Usually, you’ll use sampled data to define the sounds you want to create, because sampled data provides the greatest flexibility and variety of sounds. You might use wave-table or square-wave data for very simple sounds. For instance, the Simple Beep alert sound is defined using square-wave data. Most other alert sounds are defined using sampled-sound data.
  1487. This section also describes sound commands and sound channels, which you need to know about to be able to do anything more complex than play sound resources or files synchronously using high-level Sound Manager routines.
  1488. Sound Data
  1489.  
  1490. The Sound Manager can play sounds defined using one of three kinds of sound data:
  1491. n    square-wave data
  1492. n    wave-table data
  1493. n    sampled-sound data
  1494. This section provides a brief description of each of these kinds of audio data and introduces some of the concepts that are used in the remainder of this chapter. A complete description of the nature and format of audio data is beyond the scope of this book. There are, however, numerous books available that provide complete discussions of digital audio data.
  1495. Square-Wave Data
  1496.  
  1497. Square-wave data is the simplest kind of audio data supported by the Sound Manager. You can use square-wave data to generate a sound based on a square wave. Your application can use square-wave data to play a simple sequence of sounds in which each sound is described completely by three factors: its frequency or pitch, its amplitude (or volume), and its duration.
  1498. The frequency of a sound is the number of cycles per second (or hertz) of the sound wave. Usually, you specify a sound’s frequency by a MIDI value. MIDI note values correspond to frequencies for musical notes, such as middle C, which is defined to have a MIDI value of 60, which on Macintosh computers is equivalent to 261.625 hertz.
  1499. Pitch is a lister’s subjective interpretation of the sound’s frequency. The terms frequency and pitch are used interchangeably in this chapter.
  1500. A sound’s duration is the length of time a sound takes to play. In the Sound Manager, durations are usually specified in half-milliseconds.
  1501. The amplitude of a sound is the loudness at which it is being played. Two sounds played at the same amplitude might not necessarily sound equally loud. For example, one sound could be played at a lower volume (which the user may set with the Sound control panel). Or, a sampled sound of a fleeting whisper might sound softer than a sampled sound of continuous gunfire, even if your application plays them at the same amplitude.
  1502. Note
  1503. Amplitude is traditionally considered to be the height of a sound wave, so that two sounds with the same amplitude would always sound equally loud. However, the Sound Manager considers amplitude to be the adjustment to be made to an existing sound wave. A sound played at maximum amplitude still might sound soft if the wave amplitude is small. u
  1504. A sound’s timbre is its clarity. A sound with a low timbre is very clear; a sound with a high timbre is buzzing. Only sounds defined using square-wave data have timbres.
  1505. Wave-Table Data
  1506.  
  1507. To produce more complex sounds than are possible using square-wave data, your applications can use wave-table data. As the name indicates, wave-table data is based on a description of a single wave cycle. This cycle is called a wave table and is represented as an array of bytes that describe the timbre (or tone) of a sound at any point in the cycle.
  1508. Your application can use any number of bytes to represent the wave, but 512 is the recommended number because the Sound Manager resizes a wave table to 512 bytes if the table is not exactly that long. Your application can compute the wave table at run time or load it from a resource.
  1509. A wave table is a sequence of wave amplitudes measured at fixed intervals. For instance, a sine wave can be converted into a wave table by taking the value of the wave’s amplitude at every 1/512 interval of the wave (see Figure 2-2).
  1510. A wave table is represented as a packed array of bytes. Each byte contains a value in the range $00–$FF. These values are interpreted as offset values, where $80 represents an amplitude of 0. The largest negative amplitude is $00 and the largest positive amplitude is $FF. When playing a wave-table description of a sound, the Sound Manager loops through the wave table for the duration of the sound.
  1511. Figure 2-2    A graph of a wave table
  1512.  
  1513. Sampled-Sound Data
  1514.  
  1515. You can use sampled-sound data to play back sounds that have been digitally recorded (that is, sampled sounds) as well as sounds that are computed, possibly at run time. Sampled sounds are the most widely used of all the available sound types primarily because it is relatively easy to generate a sampled sound and because sampled-sound data can describe a wide variety of sounds. Sampled sounds are typically used to play back prerecorded sounds such as speech or special sound effects.
  1516. You can use the Sound Manager to store sampled sounds in one of two ways, either as resources of type 'snd ' or as AIFF or AIFF-C format files. The structure of resources of type 'snd ' is given in “Sound Resources” on page 2-74, and the structure of AIFF and AIFF-C files is given in “Sound Files” on page 2-81. If you simply want to play short prerecorded sampled sounds, you should probably include the sound data in 'snd ' resources. If you want to allow the user to transfer recorded sound data from one application to another (or from one operating system to another), you should probably store the sound data in an AIFF or AIFF-C file. In certain cases, you must store sampled sounds in files and not in resources. For example, a sampled sound might be too large to be stored in a resource.
  1517. Regardless of how you store a sampled sound, you can use Sound Manager routines to play that sound. If you choose to store sampled sounds in files of type AIFF or AIFF-C, you can play those sounds by calling the SndStartFilePlay function, introduced in the chapter “Introduction to Sound on the Macintosh” in this book. If you store sampled sounds in resources, your application can play those sounds by passing the Sound Manager function SndPlay a handle to a resource of type 'snd ' that contains a sampled sound header. (The SndStartFilePlay function can also play 'snd ' resources directly from disk, but this is not recommended.)
  1518. There are three types of sampled-sound headers: the standard sound header, the extended sound header, and the compressed sound header. The sound header contains information about the sample (such as the original sampling rate, the length of the sample, and so forth), together with an indication of where the sample data is to be found. The sampled sound header can reference only buffers of monophonic, 8-bit sound. The extended sound header can be used for 8- or 16-bit stereo sound data as well as monophonic sound data. The compressed sound header can be used to describe compressed sound data, whether monophonic or stereo. Data can be stored in a buffer separate from the sound resource or as part of the sound resource as the last field of the sound header.
  1519. Note
  1520. The terminology sampled sound header can be confusing because in most cases the sound header (and hence the 'snd ' resource) contains the sound data as well as information describing the data. Also, do not confuse sampled sound headers with sound resource headers. Sampled sound headers contain information about sampled-sound data, but sound resource headers contain information on the format of an entire sound resource.u 
  1521. You can play a sampled sound at its original rate or play it at some other rate to change its pitch. Once you install a sampled sound header into a channel, you can play it at varying rates to provide a number of pitches. In this way, you can use a sampled sound as a voice or instrument to play a series of sounds.
  1522. Sampled-sound data is made up of a series of sample frames, which are stored contiguously in order of increasing time. For noncompressed sound data, each sample frame contains one or more sample points. For compressed sound data, each sample frame contains one or more packets.
  1523. For multichannel sounds, a sample frame is an interleaved set of sample points or packets. (For monophonic sounds, a sample frame is just a single sample point or a single packet.) The sample points within a sample frame are interleaved by channel number. For example, the sound data for a stereo, noncompressed sound is illustrated in Figure 2-3.
  1524. Figure 2-3    Interleaving stereo sample points
  1525.  
  1526. Each sample point of noncompressed sound data in a sample frame is, for sound files, a linear, two’s complement value, and, for sound resources, a binary offset value. Sample points are from 1 to 32 bits wide. The size is usually 8 bits, but a different size can be specified in the sampleSize field of the extended sound header (for sound resources) or in the sampleSize field of the Common Chunk (for sound files). Each sample point is stored in an integral number of contiguous bytes. Sample points that are from 1 to 8 bits wide are stored in 1 byte, sample points that are from 9 to 16 bits wide are stored in 2 bytes, and so forth. When the width of a sample point is less than a multiple of 8 bits, the sample point data is left aligned (using a shift-left instruction), and the low-order bits at the right end are set to 0.
  1527. For example, for 8-bit noncompressed sound data stored in a sound resource, each sample point is similar to a value in a wave-table description. These values are interpreted as offset values, where $80 represents an amplitude of 0. The value $00 is the most negative amplitude, and $FF is the largest positive amplitude.
  1528. Each packet of 3:1 compressed sound data is 2 bytes; a packet of 6:1 compressed sound is 1 byte. These byte sizes are defined in bits by the constants threeToOnePacketSize and sixToOnePacketSize, respectively. 
  1529. Sound Commands
  1530.  
  1531. The Sound Manager provides routines that allow you to create and dispose of sound channels. These routines allow you to manipulate sound channels, but they do not directly produce any sounds. To actually produce sounds, you need to issue sound commands. A sound command is an instruction to produce sound, modify sound, or otherwise assist in the overall process of sound production. For example, the ampCmd sound command changes the amplitude (or volume) of a sound.
  1532. You can issue sound commands in several ways. You can send sound commands one at a time into a sound channel by repeatedly calling the SndDoCommand function. The commands are held in a queue and processed in a first-in, first-out order. Alternatively, you can bypass a sound queue altogether by calling the SndDoImmediate function. You can also issue sound commands by calling the function SndPlay and specifying a sound resource of type 'snd ' that contains the sound commands you want to issue. A sound resource can contain any number of sound commands. As a result, you might be able to accomplish all sound-related activity simply by creating sound resources and calling SndPlay in your application. See “Sound Resources” on page 2-74 for details on the format of an 'snd ' resource.
  1533. Generally speaking, no matter how sound commands are issued, they are all eventually sent to the Sound Manager, which interprets the commands and plays the sound on the available audio hardware. The Sound Manager provides a rich set of sound commands. The structure of a sound command is defined by the SndCommand data type:
  1534. TYPE SndCommand =
  1535. PACKED RECORD
  1536.     cmd:                Integer;                {command number}
  1537.     param1:                Integer;                {first parameter}
  1538.     param2:                LongInt;                {second parameter}
  1539. END;
  1540. Commands are always 8 bytes in length. The first 2 bytes are the command number, and the next 6 make up the command’s options. The format of the last 6 bytes depends on the command in use, although typically those 6 bytes are interpreted as an integer followed by a long integer. For example, an application can install a wave table into a sound channel by using SndDoCommand with a sound command whose cmd field is the waveTableCmd constant. In that case, the param1 field specifies the length of the wave table, and the param2 field is a pointer to the wave-table data itself. Other sound commands may interpret the 6 parameter bytes differently or may not use them at all.
  1541. The sound commands available to your application are defined by constants.
  1542. CONST
  1543.     nullCmd                        = 0;            {do nothing}
  1544.     quietCmd                        = 3;            {stop a sound that is playing}
  1545.     flushCmd                        = 4;            {flush a sound channel}
  1546.     reInitCmd                        = 5;            {reinitialize a sound channel}
  1547.     waitCmd                        = 10;            {suspend processing in a channel}
  1548.     pauseCmd                        = 11;            {pause processing in a channel}
  1549.     resumeCmd                        = 12;            {resume processing in a channel}
  1550.     callBackCmd                        = 13;            {execute a callback procedure}
  1551.     syncCmd                        = 14;            {synchronize channels}
  1552.     availableCmd                        = 24;            {see if initialization options are supported}
  1553.     versionCmd                        = 25;            {determine version}
  1554.     totalLoadCmd                        = 26;            {report total CPU load}
  1555.     loadCmd                        = 27;            {report CPU load for a new channel}
  1556.     freqDurationCmd                        = 40;            {play a note for a duration}
  1557.     restCmd                        = 41;            {rest a channel for a duration}
  1558.     freqCmd                        = 42;            {change the pitch of a sound}
  1559.     ampCmd                        = 43;            {change the amplitude of a sound}
  1560.     timbreCmd                        = 44;            {change the timbre of a sound}
  1561.     getAmpCmd                        = 45;            {get the amplitude of a sound}
  1562.     volumeCmd                        = 46;            {set volume}
  1563.     getVolumeCmd                        = 47;            {get volume}
  1564.     waveTableCmd                        = 60;            {install a wave table as a voice}
  1565.     soundCmd                        = 80;            {install a sampled sound as a voice}
  1566.     bufferCmd                        = 81;            {play a sampled sound}
  1567.     rateCmd                        = 82;            {set the pitch of a sampled sound}
  1568.     getRateCmd                        = 85;            {get the pitch of a sampled sound}
  1569. For details on individual sound commands, see the relevant sections in “Using the Sound Manager” beginning on page 2-17. Also see “Sound Command Numbers” beginning on page 2-92 for a complete summary of the available sound commands, their parameters, and their uses.
  1570. Sound Channels
  1571.  
  1572. A sound channel is a queue of sound commands that is managed by the Sound Manager, together with other information about the sounds to be played in that channel. The commands placed into the channel might originate from an application or from the Sound Manager itself. The commands in the queue are passed one by one, in a first-in, first-out (FIFO) manner, to the Sound Manager for interpretation and processing.
  1573. The Sound Manager uses the SndChannel data type to define a sound channel.
  1574. TYPE SndChannel =
  1575. PACKED RECORD
  1576.     nextChan:                    SndChannelPtr;                    {pointer to next channel}
  1577.     firstMod:                    Ptr;                    {used internally}
  1578.     callBack:                    ProcPtr;                    {pointer to callback procedure}
  1579.     userInfo:                    LongInt;                    {free for application's use}
  1580.     wait:                    LongInt;                    {used internally}
  1581.     cmdInProgress:                    SndCommand;                    {used internally}
  1582.     flags:                    Integer;                    {used internally}
  1583.     qLength:                    Integer;                    {used internally}
  1584.     qHead:                    Integer;                    {used internally}
  1585.     qTail:                    Integer;                    {used internally}
  1586.     queue:                    ARRAY[0..stdQLength-1] OF SndCommand;
  1587. END; 
  1588. Most of the fields of the sound channel record are used internally by the Sound Manager, and you should not access or change them. However, your application is free to use the userInfo field to store any information that you wish to associate with a sound channel. For example, you might store a handle to an application-defined record that contains information about how your application is using the channel.
  1589. Some applications do not need to worry about creating or disposing of sound channels because the high-level Sound Manager routines take care of these automatically. However, if you wish to customize sound output or play sounds asynchronously, you must create your own sound channels (with the SndNewChannel function).
  1590. The enhanced Sound Manager included in system software versions 6.0.7 and later provides the ability to have multiple channels of sampled sound produce output on the Macintosh audio hardware concurrently. (Previous versions of the Sound Manager could play only a single channel of sampled sound at a time.) This allows a layering of sound that can bring a touch of reality to a simulation or presentation and permits applications to incorporate synthesized speech output with any other kind of Macintosh-generated sound. Sound Manager version 3.0 extended this capability to allow multiple channels of any kind of sound data to play simultaneously.
  1591. Your application can open several channels of sound for concurrent output on the available audio hardware. Similarly, multiple applications can each open channels of sound. The number and quality of concurrent channels of sound are limited only by the abilities of the machine, particularly by the speed of the CPU. Different Macintosh computers have different CPU clock speeds and execute instructions at quite different rates. This means that some machines can manage more channels of sound and produce higher-quality sound than other machines. For example, a Macintosh Quadra might be able to support several channels of high-quality stereo sound without significant impact on other processing, whereas a Macintosh Plus might be able to support only a single channel of monophonic sound before other processing slows significantly. 
  1592. The Sound Manager currently supports multiple channels of sound only on machines equipped with an Apple Sound Chip or equivalent hardware. To maintain maximum compatibility between machines for your applications, you should always check the operating environment to make sure that the ability to play multiple channels of sampled sound is present before attempting to do so. A technique for determining whether your application can play multiple channels of sound is described in “Testing for Multichannel Sound and Play-From-Disk Capabilities” on page 2-35.
  1593. Sound Compression and Expansion
  1594.  
  1595. One minute of monophonic sound recorded with the fidelity you would expect from a commercial compact disc occupies about 5.3 MB of disk space. One minute of sound digitized by the current low-fidelity digitizing peripherals for Macintosh computers occupies more than 1 MB of disk space. Even one minute of telephone-quality speech takes up more than half of a megabyte on a disk. Despite the increased capacities of mass-storage devices, disk space can be a problem if your application incorporates large amounts of sampled sound. The space problem is particularly acute for multimedia applications. Because a large portion of the space occupied by a multimedia application is likely to be taken up by sound data, the complexity and richness of the application’s sound component are limited.
  1596. To help remedy this problem, the Sound Manager includes a set of routines known collectively as Macintosh Audio Compression and Expansion (MACE). MACE enables you to provide more audio information in a given amount of storage space by allowing you to compress sound data and then expand it for playback. These enhancements are based entirely in software and require no specialized hardware.
  1597. The audio compression and expansion features allow you to enhance your application by including more audio data. MACE also relieves some distribution problems by reducing the number of disks required for shipping an application that relies heavily on sound. MACE has made some kinds of applications, such as talking dictionaries and foreign language-instruction software, more feasible than before.
  1598. MACE adds three main kinds of capabilities to those already present in the Sound Manager: audio data compression, real-time expansion and playback of compressed audio data, and buffered expansion and playback of compressed audio data.
  1599. n    Compression. The Sound Manager can compress a buffer of digital audio data either in the original buffer or in a separate buffer. If a segment of audio data is too large to fit into a single buffer, your application can make repeated calls to the compression routine.
  1600. n    Real-time expansion playback. The Sound Manager can expand compressed audio data contained in a small internal buffer and play it back at the same time. Because the audio data expansion and playback occur at the same time, there is more of a strain on the CPU when using this method of sound expansion rather than buffered expansion.
  1601. n    Buffered expansion. The Sound Manager can expand a specified buffer of compressed audio data and store the result in a separate buffer. The expanded buffer can then be played back using other Sound Manager routines with minimal processor overhead during playback. Applications that require screen updates or user interaction during playback (such as animation or multimedia applications) should use buffered expansion.
  1602. MACE provides audio data compression and expansion capabilities in ratios of either 3:1 or 6:1 for all currently supported Macintosh models, from the Macintosh Plus forward. The principal tradeoff when using MACE is that the expanded audio data suffers a loss of fidelity in comparison to the original data. A small amount of noise is introduced into a 3:1 compressed sound when it is expanded and played back, and a greater amount of noise for the 6:1 ratio. The 3:1 buffer-to-buffer compression and expansion option is well suited for high-fidelity sounds. The 6:1 buffer-to-buffer compression and expansion option provides greater compression at the expense of lower-fidelity results and is recommended for voice data only. This technique reduces the frequency bandwidth of the audio signal by a factor of two to achieve the higher compression ratio.
  1603. MACE allows for the compression of both monophonic and stereo sounds. However, some Macintosh computer models (such as the Macintosh Plus and Macintosh SE) cannot expand stereo sounds.
  1604. Note
  1605. With Sound Manager versions prior to 3.0, some Macintosh computers play only the right channel of stereo 'snd ' data through the internal speaker. Certain Macintosh II models can play only a single channel through the internal speaker. Sound Manager version 3.0 removes both of these limitations.u 
  1606. Existing applications that use the Sound Manager’s SndPlay function to play digitized audio signals can play compressed audio signals without modification or recompilation.
  1607. The MACE routines assume that each original sample consists of 8-bit sound in binary offset format. The compression techniques do not, however, depend on a particular sample rate (the rate at which samples are recorded). Table 2-1 shows some common sample rates, expressed both as hertz and as unsigned fixed-point values.
  1608. Table 2-1    Sample rates
  1609. Rate (Hz)    Sample rate value (Fixed)    
  1610. 44100.00000    $AC440000    
  1611. 22254.54545    $56EE8BA3    
  1612. 22050.00000    $56EE8BA3    
  1613. 11127.27273    $2B7745D1    
  1614. 11025.00000    $2B110000    
  1615. 7418.1818    $1CFA2E8B    
  1616. 5563.6363    $15BBA2E8    
  1617.  
  1618. The Sound Manager defines constants for the most common sample rates:
  1619. CONST
  1620.     rate44khz                        = $AC440000;                    {44100.00000 in fixed-point}
  1621.     rate22khz                        = $56EE8BA3;                    {22254.54545 in fixed-point}
  1622.     rate22050hz                        = $56220000;                    {22050.00000 in fixed-point}
  1623.     rate11khz                        = $2B7745D1;                    {11127.27273 in fixed-point}
  1624.     rate11025hz                        = $2B110000;                    {11025.00000 in fixed-point}
  1625. The compression techniques produce their best quality output when the sample rate is the same as the output rate of the sound hardware of the machine playing the audio data. The output rate used in most current Macintosh computers is 22.254 kilohertz (hereafter referred to as the 22 kHz rate). Because of speed limitations, the Macintosh Plus and Macintosh SE cannot perform sample-rate conversion during expansion playback. On those machines, all sounds are played back at a 22 kHz rate. To provide consistent quality in sounds that might be played on different machines, you should record all sounds at a 22 kHz sample rate.
  1626. The MACE algorithms are optimized to provide the best sound quality possible through the internal speaker in real time. However, the user who employs high-quality speakers might notice a high-frequency hiss for some sounds compressed at the 3:1 ratio. This hiss results from a design tradeoff between maintaining real-time operation on the Macintosh Plus and preserving as much frequency bandwidth of the signal as possible. If you think that your output might be played on high-quality speakers, you might want to filter out the hiss before compression by passing the audio output through an equalizer that removes frequencies above 10 kHz. When you use the 6:1 compression and expansion ratio, your frequency response is cut in half. For example, when you use the 22 kHz sample rate, the highest frequency possible would normally be 11 kHz; however, after compressing and expanding the data at the 6:1 ratio, the highest frequency you could get would be only 5.5 kHz.
  1627. Note
  1628. The Sound Manager uses compressions and decompression components (codecs) to handle the MACE capabilities. You can provide custom codecs to use other compression and decompression algorithms. See the chapter “Sound Components” in this book for information on developing audio codecs.u
  1629.  
  1630. Using the Sound Manager
  1631.  
  1632. The Sound Manager provides a wide variety of methods for creating sound and manipulating audio data on Macintosh computers. Usually, your application needs to use only a few of the many routines or sound commands that are available.
  1633. The Sound Manager routines can be divided into high-level routines and low-level routines. The high-level routines (like SndPlay and SysBeep) give you the ability to produce very complex audio output at very little programming expense. The majority of applications interact with the Sound Manager using these high-level routines, which allow you to play sounds without knowing anything about the structure of sound commands or sampled-sound data. You can let the high-level routines automatically allocate channels, or, for increased control, you can allocate your own sound channels.
  1634. Applications that have more sophisticated sound capabilities use the low-level routines (like SndDoCommand and SndDoImmediate) to send sound commands to sound channels. For example, your application might send a sound command to alter the amplitude of a sound that is playing (or is about to play).
  1635. Finally, a few very specialized applications use the Sound Manager’s low-level sound playback routines, which allow fine-tuning of the algorithms the Sound Manager uses to manage the double buffering of sound for its play-from-disk routines. 
  1636. In general, you should use the highest-level routines capable of producing the kind of sound you want. Many applications can simply play sounds stored in resources or files and do not need to customize the sounds or continue with other processing while those sounds are playing. In such cases, you can use the high-level Sound Manager routines, as illustrated in the chapter “Introduction to Sound on the Macintosh” in this book. If, however, you need to be able to exercise very fine control over sound output or to play sounds asynchronously, you must manage your own sound channels. See “Managing Sound Channels” on page 2-19 to learn how you can use the Sound Manager to
  1637. n    allocate and dispose of sound channels manually by using the SndNewChannel and SndDisposeChannel functions
  1638. n    manipulate sound that is playing (for example, by sending the ampCmd command to a sound channel to change the amplitude of sound playing)
  1639. n    stop sounds and flush sound channels by using the quietCmd and flushCmd commands
  1640. n    pause and restart sound channels by using the pauseCmd and resumeCmd commands
  1641. n    synchronize sound channels by using the syncCmd command
  1642. As you’ve learned, the capabilities of the Sound Manager vary greatly from one Macintosh computer to another, depending on which version of the Sound Manager is available on a particular computer and on what audio hardware is available. To create sounds effectively on all computers, you might need to obtain information about the available sound features. “Obtaining Sound-Related Information” on page 2-32 explains how you can
  1643. n    use the Gestalt function to determine which basic sound features are available
  1644. n    find the version number of the available Sound Manager or of the MACE compression and expansion routines
  1645. n    determine whether your application can take advantage of multichannel sound and the play-from-disk routines
  1646. n    obtain information about a single sound channel
  1647. Some applications need to be able to play computer-generated tones at different pitches. In addition, some applications need to play waveforms or sampled sounds at different pitches. For example, if you are writing an application that converts musical notes to sound, you might record the sound of a violin playing middle C and then replay the sound at a variety of pitches to simulate a violinist’s playing a concerto. The Sound Manager allows you to do this by allocating a sound channel and sending sound commands to it. “Playing Notes” on page 2-41 explains how you can
  1648. n    play simple sequences of notes by using the freqCmd and freqDurationCmd commands
  1649. n    install waveforms or sampled sounds into channels by using the soundCmd and waveTableCmd commands so that you can play them at different frequencies
  1650. n    set a sound resource’s loop points so that the sound repeats if a freqCmd or freqDurationCmd command lasts longer than the sound
  1651. Although some applications do not need to do other processing while sounds are playing, others do. If your application allocates sound channels itself, it can request that the Sound Manager play sounds asynchronously. By using callback procedures and completion routines, your application can arrange for a sound channel to be disposed when a sound finishes playing. “Playing Sounds Asynchronously” on page 2-46 explains how you can
  1652. n    play a sound resource asynchronously by defining a callback procedure
  1653. n    use callback procedures to synchronize sounds you play asynchronously with other actions
  1654. n    play a sound file asynchronously and pause, restart, or stop such an asynchronous playback
  1655. n    manage multiple channels of sound to play more than one sound asynchronously at the same time
  1656. The high-level Sound Manager routines automatically parse sound resources and sound files to determine the information the Sound Manager needs to play the sounds contained in the resources and files. However, you might need to obtain information about sound resources or sound files for some other reason. Or, you might need to locate a certain part of a sound resource or sound file. For example, to use the bufferCmd sound command to play a buffer of sampled sound, you must obtain a pointer to the sound header contained in that buffer. See the section “Parsing Sound Resources and Sound Files” on page 2-56 for information on how to
  1657. n    parse sound resources containing sampled-sound data to obtain information from the sampled-sound data’s sound header
  1658. n    use the bufferCmd command to play sampled-sound data stored within a sound resource
  1659. n    parse sound files to find a particular chunk and to extract the data from that chunk
  1660. High-level Sound Manager routines automatically expand sound data in real time when playing compressed sounds. However, you might need to manually compress or expand sound data at a time when you are not playing sounds. “Compressing and Expanding Sounds” on page 2-66 explains how you can use the Sound Manager’s built-in sound compression and expansion routines to compress or expand sounds.
  1661. The Sound Manager’s high-level play-from-disk routines use highly optimized algorithms to manage the double buffering of data so that the play from disk is continuous and without audible gaps. However, if you wish to bypass the high-level Sound Manager play-from-disk routines, you may define your own double-buffering routines. This might be useful if you need to change the sound data on disk before the Sound Manager can process it. The section “Using Double Buffers” on page 2-68 explains how you can set up your own double buffers and use a doubleback procedure to bypass the normal play-from-disk routines.
  1662. Managing Sound Channels
  1663.  
  1664. To use most of the low-level Sound Manager routines, you must specify a sound channel that maintains a queue of commands. Also, to take advantage of the full capabilities of the high-level Sound Manager routines, including asynchronous sound play, you must allocate your own sound channels. This section explains how your application can allocate, dispose of, and use its own sound channels.
  1665. This section first describes how you can allocate and dispose of sound channels. Then it explains how you can manipulate sounds playing in sound channels, stop sounds playing in sound channels, and pause and restart the execution of sounds in sound channels.
  1666. Allocating Sound Channels
  1667.  
  1668. Usually, you do not need to worry about allocating memory for sound channels because the SndNewChannel function automatically allocates a sound channel record in the application’s heap if passed a pointer to a NIL sound channel. SndNewChannel also internally allocates memory for the sound channel’s queue of sound commands. For example, the following lines of code request that the Sound Manager open a new sound channel for playing sampled sounds:
  1669. mySndChan := NIL;
  1670. myErr := SndNewChannel(mySndChan, sampledSynth, 0, NIL);
  1671. If you are concerned with managing memory yourself, you can allocate your own memory for a sound channel record and pass the address of that memory as the first parameter to SndNewChannel. By allocating a sound channel record manually, you not only obtain control over the allocation of the sound channel record, but you can specify the size of the queue of sound commands that the Sound Manager internally allocates. Listing 2-1 illustrates one way to do this.
  1672. Listing 2-1    Creating a sound channel
  1673.  
  1674. FUNCTION MyCreateSndChannel (synth: Integer; initOptions: LongInt;
  1675.                                         userRoutine: ProcPtr; 
  1676.                                         queueLength: Integer): SndChannelPtr;
  1677. VAR
  1678.     mySndChan:                SndChannelPtr;                        {pointer to a sound channel}
  1679.     myErr:                OSErr;
  1680. BEGIN
  1681.     {Allocate memory for sound channel.}
  1682.     mySndChan := SndChannelPtr(NewPtr(Sizeof(SndChannel)));
  1683.     IF mySndChan <> NIL THEN
  1684.     BEGIN
  1685.         mySndChan^.qLength := queueLength;                                                {set number of commands in queue}
  1686.         {Create a new sound channel.}
  1687.         myErr := SndNewChannel(mySndChan, synth, initOptions, userRoutine);
  1688.         IF myErr <> noErr THEN
  1689.         BEGIN                                                {couldn't allocate channel}
  1690.             DisposePtr(Ptr(mySndChan));                                            {free memory already allocated}
  1691.             mySndChan := NIL;                                            {return NIL}
  1692.         END
  1693.         ELSE
  1694.             mySndChan^.userInfo := 0;                                            {reset userInfo field}
  1695.     END;
  1696.     MyCreateSndChannel := mySndChan;                                                    {return new sound channel}
  1697. END;
  1698. The MyCreateSndChannel function defined in Listing 2-1 first allocates memory for a sound channel record and then calls the SndNewChannel function to attempt to allocate a channel. Note that MyCreateSndChannel checks the result code returned by SndNewChannel to determine whether the function was able to allocate a channel. The SndNewChannel function might not be able to allocate a channel if there are so many channels open that allocating another would put too much strain on the CPU. Also, SndNewChannel might fail if memory is low. (In addition to the memory for a sound channel record that is passed in the first parameter to SndNewChannel, the function must internally allocate memory in which to store sound commands.)
  1699. If you allocate memory for a sound channel record, you should specify the size of the queue of sound commands by assigning a value to the qLength field of the sound channel record you allocate. You can use the constant stdQLength to obtain a standard queue of 128 sound commands, or you can provide a value of your own. 
  1700. CONST
  1701.     stdQLength                             = 128;            {default size of a sound channel}
  1702. If you know that your application will play only resources containing sampled sound, you might set the qLength field to a considerably lower value, because resources created with the SndRecord function (described in the chapter “Introduction to Sound on the Macintosh” in this book) contain only one sound command, the bufferCmd command, which specifies that a buffer of sound should be played. For example, if your application uses a sound channel only to play a single sampled sound asynchronously, you can set qLength to 2, to allow for the bufferCmd command and a callBackCmd command that your application issues manually, as described in “Playing Sounds Asynchronously” on page 2-46. By using a smaller than standard queue length, your application can conserve memory.
  1703. Note
  1704. The number of sound commands in a channel should be an integer greater than 0. If you open a channel with a 0-length queue, most of the Sound Manager routines will return a badChannel result code.u 
  1705. IMPORTANT
  1706. In general, however, you should let the Sound Manager allocate sound channel records for you. The amount of memory you might save by allocating your own is usually negligible.s
  1707. The second parameter in the SndNewChannel function specifies the kind of data you want to play on that channel. You can specify one of the following constants:
  1708. CONST
  1709.     squareWaveSynth                        = 1;            {square-wave data}
  1710.     waveTableSynth                        = 3;            {wave-table data}
  1711.     sampledSynth                        = 5;            {sampled-sound data}
  1712. In some versions of system software prior to system software version 7.0 (including system software version 6.0.7), high-level Sound Manager routines do not work properly with sound resources that specify the sound data type twice. This might happen if a resource specifies that a sound consists of sampled-sound data and an application does the same when creating a sound channel. This might also happen if an application uses the same sound channel to play several sound resources that contain different kinds of sound data. There are several solutions to this problem that you can use if you must maintain compatibility with old versions of system software:
  1713. n    If your application plays only sampled-sound resources, then you need only ensure that none of the sound resources specifies that it contains sampled-sound data. Then, when you create a sound channel, pass sampledSynth as the second parameter to SndNewChannel so that the Sound Manager interprets the data in the sound resources correctly. Do not use the SndPlay routine.
  1714. n    If your application must be able to play sampled-sound resources as well as resources that contain square-wave or wave-table data, ensure that all sound resources that your application uses specify their data type. (Sound resources created with the Sound Input Manager automatically specify that they contain sampled-sound data.) Then, when creating a channel in which you plan to play a sound resource, pass 0 as the second parameter to SndNewChannel, and then use the channel to play no more than one sound resource. 
  1715. n    If you do not wish to modify your application’s sound resources, and your application plays only sampled-sound resources, then you can play sounds with low-level Sound Manager routines, a technique described in “Playing Sounds Using Low-Level Routines” on page 2-61. 
  1716. Note that this problem does not occur with sound files, because sound files always contain sampled-sound data and thus do not explicitly declare their data type. As a result, when creating a channel in which you plan to play a sound file, pass sampledSynth as the second parameter to SndNewChannel.
  1717. The third parameter in the SndNewChannel function specifies the initialization parameters to be associated with the new channel. These are discussed in the following section. The fourth parameter in the SndNewChannel function is a pointer to a callback procedure. If your application produces sounds asynchronously or needs to be alerted when a command has completed, you can specify a callback procedure by passing the address of that procedure in the fourth parameter and then by installing a callback procedure into the sound channel. If you pass NIL as the fourth parameter, then no callback procedure is associated with the channel. See “Playing Sounds Asynchronously” on page 2-46 for more information on setting up and using callback procedures.
  1718. Initializing Sound Channels
  1719.  
  1720. When you first create a sound channel with SndNewChannel, you can request that the channel have certain characteristics as specified by a sound channel initialization parameter. For example, to indicate that you want to allocate a channel capable of producing stereo sound, you might use the following code:
  1721. myErr := SndNewChannel(mySndChan, sampledSynth, initStereo, NIL);
  1722. These are the currently recognized constants for the sound channel initialization parameter.
  1723. CONST
  1724.     initChanLeft                        = $0002;                {left stereo channel}
  1725.     initChanRight                        = $0003;                {right stereo channel}
  1726.     waveInitChannel0                        = $0004;                {wave-table channel 0}
  1727.     waveInitChannel1                        = $0005;                {wave-table channel 1}
  1728.     waveInitChanne12                        = $0006;                {wave-table channel 2}
  1729.     waveInitChannel3                        = $0007;                {wave-table channel 3}
  1730.     initMono                        = $0080;                {monophonic channel}
  1731.     initStereo                        = $00C0;                {stereo channel}
  1732.     initMACE3                        = $0300;                {3:1 compression}
  1733.     initMACE6                        = $0400;                {6:1 compression}
  1734.     initNoInterp                        = $0004;                {no linear interpolation}
  1735.     initNoDrop                        = $0008;                {no drop-sample conversion}
  1736. See “Channel Initialization Parameters” beginning on page 2-91 for a complete description of these constants.
  1737. Note
  1738. Some Macintosh computers play only the left channel of stereo sounds out the internal speaker. Other machines (for example, the Macintosh SE/30 and Macintosh IIsi) mix both channels together before sending a signal to the internal speaker. You can use the Gestalt function to determine if a particular machine mixes both left and right channels to the internal speaker. All Macintosh computers except the Macintosh SE and the Macintosh Plus, however, play stereo signals out the headphone jack.u 
  1739. The initialization parameters are additive. To initialize a channel for stereo sound with no linear interpolation, simply pass an initialization parameter that is the sum of the desired characteristics, as follows:
  1740. myErr := SndNewChannel(mySndChan, sampledSynth, 
  1741.                                 initStereo+initNoInterp, NIL);
  1742. A call to SndNewChannel is really only a request that the Sound Manager open a channel having the desired characteristics. It is possible that the parameters requested are not available. In that case, SndNewChannel returns a notEnoughHardwareErr error. In general, you should pass 0 as the third parameter to SndNewChannel unless you know exactly what kind of sound is to be played.
  1743. You can alter certain initialization parameters, even while a channel is actively playing a sound, by issuing the reInitCmd command. For example, you can change the output channel from left to right, as shown in Listing 2-2.
  1744. Listing 2-2    Reinitializing a sound channel
  1745.  
  1746. VAR
  1747.     mySndCmd:                        SndCommand;
  1748.     mySndChan:                        SndChannelPtr;
  1749.     myErr:                         OSErr;
  1750. .
  1751. .
  1752. .
  1753. mySndCmd.cmd := reInitCmd;
  1754. mySndCmd.param1 := 0;                                                            {unused}
  1755. mySndCmd.param2 := initChanRight;                                                            {new init parameter}
  1756. myErr := SndDoImmediate(mySndChan, mySndCmd);
  1757. The reInitCmd command accepts the initNoInterp constant to toggle linear interpolation on and off; it should be used with noncompressed sounds only. If an noncompressed sound is playing when you send a reInitCmd command with this constant, linear interpolation begins immediately. You can also pass initMono, initChanLeft, or initChanRight to pan to both channels, to the left channel, or to the right channel. This affects only monophonic sounds. The Sound Manager remembers the settings you pass and applies them to all further sounds played on that channel.
  1758. Releasing Sound Channels
  1759.  
  1760. To dispose of a sound channel that you have allocated with SndNewChannel, use the SndDisposeChannel function. SndDisposeChannel requires two parameters, a pointer to the channel that is to be disposed and a Boolean value that indicates whether the channel should be flushed before disposal. Here’s an example:
  1761. myErr := SndDisposeChannel(mySndChan, TRUE);
  1762. Because the second parameter is TRUE, the Sound Manager sends both a flushCmd command and a quietCmd command to the sound channel (using SndDoImmediate). This removes all commands from the sound channel and stops any sound already in progress. Then the Sound Manager disposes of the channel.
  1763. If the second parameter is FALSE, the Sound Manager simply queues a quietCmd command (using SndDoCommand) and waits until quietCmd is received by the channel before disposing of the channel. In this case, the SndDisposeChannel function does not return until the channel has finished processing commands and the queue is empty.
  1764. sWARNING
  1765. If you dispose of a channel currently playing from disk, then your completion routine will still execute, but will receive a pointer to a sound channel that no longer exists. Thus, you should stop a play from disk before disposing of a channel. See “Managing an Asynchronous Play From Disk” on page 2-52 for more information on completion routines.s
  1766. Although the SndDisposeChannel function always releases memory reserved for sound commands, SndDisposeChannel cannot release memory associated with a sound channel record if you have allocated that memory yourself. For example, if you use the MyCreateSndChannel function defined in Listing 2-1 to create a sound channel, you must dispose first of the sound channel and then of the memory occupied by the sound channel record, as illustrated in Listing 2-3.
  1767. Listing 2-3    Disposing of memory associated with a sound channel
  1768.  
  1769. FUNCTION MyDisposeSndChannel (sndChan: SndChannelPtr; quietNow: Boolean): 
  1770.                                             OSErr;
  1771. VAR
  1772.     myErr:            OSErr;
  1773. BEGIN
  1774.     myErr := SndDisposeChannel(sndChan, quietNow);                                                                {dispose of channel}
  1775.     DisposePtr(Ptr(sndChan));                                                                {dispose of channel ptr}
  1776.     MyDisposeSndChannel := myErr;
  1777. END;
  1778. If you have played a sound resource through a channel, the SndDisposeChannel function does not free the memory taken by the resource. You must call the Resource Manager’s ReleaseResource function to do so, or, if you have detached a resource from a resource file, you could free the memory by making the handle unlocked and purgeable. Note that if you play a sound resource asynchronously, you should not release the memory occupied by the resource until the sound finishes playing or the sound might not play properly. For information on releasing a sound resource after playing a sound asynchronously, see “Playing Sounds Asynchronously” on page 2-46.
  1779. IMPORTANT
  1780. In Sound Manager versions 3.0 and later, you can play sounds in any number of sound channels. In earlier Sound Manager versions, however, only one kind of sound can be played at one time. This results in several important restrictions on your application. In Sound Manager version 2 and earlier, you should create sound channels just before playing sounds. Once the sound is completed, you should dispose of the channel. If your application is switched out and does not release a sound channel, then other applications may be unable to open sound channels. In particular, the system alert sound might not be heard and the user might not be notified of important system occurrences. In general, while it is acceptable to issue a number of sound commands to the same sound channel, it’s not a good idea to play more than one sampled sound on the same sound channel.s 
  1781. Manipulating a Sound That Is Playing
  1782.  
  1783. The Sound Manager provides a number of sound commands that you can use to change some of the characteristics of sounds that are currently playing. For example, you can alter the rate at which a sampled sound is played back, thereby lowering or increasing the pitch of the sound. You can also pause or stop a sound that is currently in progress. See “Pausing and Restarting Sound Channels” on page 2-29 for information on how to pause the processing of a sound channel.
  1784. You can use the getRateCmd command to determine the rate at which a sampled sound is currently playing. If SndDoImmediate returns noErr when you pass getRateCmd, the current sample rate of the channel is returned as a Fixed value in the location that is pointed to by param2 of the sound command. (As usual, the high bit of that value returned is not interpreted as a sign bit.) Values that specify sampling rates are always interpreted relative to the 22 kHz rate. That is, the Fixed value $00010000 indicates a rate of 22 kHz. The value $00020000 indicates a rate of 44 kHz. The value $00008000 indicates a rate of 11 kHz.
  1785. To modify the pitch of a sampled sound currently playing, use the rateCmd command. The current pitch is set to the rate specified in the param2 field of the sound command. Listing 2-4 illustrates how to halve the frequency of a sampled sound that is already playing. Note that sending the rateCmd command before a sound plays has no effect.
  1786. Listing 2-4    Halving the frequency of a sampled sound
  1787.  
  1788. FUNCTION MyHalveFreq (mySndChan: SndChannelPtr): OSErr;
  1789. VAR
  1790.     myRate:                LongInt;                        {rate of sound play}
  1791.     mySndCmd:                SndCommand;                        {a sound command}
  1792.     myErr:                OSErr;
  1793. BEGIN
  1794.     {Get the rate of the sample currently playing.}
  1795.     mySndCmd.cmd := getRateCmd;                                        {the command is getRateCmd}
  1796.     mySndCmd.param1 := 0;                                        {unused}
  1797.     mySndCmd.param2 := LongInt(@myRate);
  1798.     myErr := SndDoImmediate(mySndChan, mySndCmd);
  1799.  
  1800.     IF myErr = noErr THEN
  1801.     BEGIN
  1802.         {Halve the sample rate.}
  1803.         mySndCmd.cmd := rateCmd;                                    {the command is rateCmd}
  1804.         mySndCmd.param1 := 0;                                    {unused}
  1805.         mySndCmd.param2 := FixDiv(myRate, $00020000);
  1806.         myErr := SndDoImmediate(mySndChan, mySndCmd);
  1807.     END;
  1808.     MyHalveFreq := myErr;
  1809. END;
  1810. When you halve the frequency of a sampled sound using the technique in Listing 2-4, the sound will play one octave lower than before. In addition, the sound will play twice as slowly as before. Likewise, if you use the rateCmd command to double the frequency of a sound, it plays one octave higher and twice as fast. Using rateCmd in this way is like pressing the fast forward button on a tape player while the play button remains depressed.
  1811. You can also use rateCmd and getRateCmd to pause a sampled sound that is currently playing. To do this, read the rate at which it is playing, issue a rateCmd command with a rate of 0, and then issue a rateCmd command with the previous rate when you want the sound to resume playing.
  1812. To change the amplitude (or loudness) of the sound in progress, issue the ampCmd command. (See Listing 2-5 for an example.) If no sound is currently playing, ampCmd sets the amplitude of the next sound. Specify the desired new amplitude in the param1 field of the sound command as a value in the range 0 to 255. 
  1813. Listing 2-5    Changing the amplitude of a sound channel
  1814.  
  1815. PROCEDURE MySetAmplitude (chan: SndChannelPtr; myAmp: Integer);
  1816. VAR
  1817.     mySndCmd:                 SndCommand;                    {a sound command}
  1818.     myErr:                 OSErr;
  1819. BEGIN
  1820.     IF chan <> NIL THEN
  1821.     BEGIN
  1822.         WITH mySndCmd DO
  1823.         BEGIN
  1824.             cmd := ampCmd;                            {the command is ampCmd}
  1825.             param1 := myAmp;                            {desired amplitude}
  1826.             param2 := 0;                            {ignored}
  1827.         END;
  1828.         myErr := SndDoImmediate(chan, mySndCmd);
  1829.         IF myErr <> noErr THEN
  1830.             DoError(myErr);
  1831.     END;
  1832. END;
  1833. If your application has an option that allows users to turn off sound output, you could call the MySetAmplitude procedure on all open channels to set the amplitude of all channels to 0. Note that the Sound control panel allows the user to adjust the sound from 0 (softest) to 7 (loudest). This value is independent of the values used for amplitudes of sounds playing in channels, and the Sound Manager uses the Sound control panel value jointly with the amplitude of a sound channel to determine how loudly to play a sound. Sounds with low frequencies sound softer than sounds with high frequencies even if the sounds play at the same amplitude. If the amplitude of a sound is 0, the sound hardware produces no sound; however, when the value set in the Sound control panel is 0, sound might still play, depending on the amplitude.
  1834. You can use the getAmpCmd command to determine the current amplitude of a sound in progress. The getAmpCmd command is similar to getRateCmd, except that the value returned is an integer. The value returned in param2 is in the range 0–255. Listing 2-6 shows an example:
  1835. Listing 2-6    Getting the amplitude of a sound in progress
  1836.  
  1837. VAR
  1838.     myAmp:            Integer;
  1839. BEGIN
  1840.     mySndCmd.cmd := getAmpCmd;
  1841.     mySndCmd.param1 := 0;                                                        {unused}
  1842.     mySndCmd.param2 := LongInt(@myAmp);
  1843.     myErr := SndDoImmediate(mySndChan, mySndCmd);
  1844. END;
  1845. To modify the timbre of a sound defined using by square-wave data, use the timbreCmd command. A sine wave is specified as 0 in param1 and produces a very clear sound. A value of 254 in param1 represents a modified square wave and produces a buzzing sound. To avoid a bug in some versions of the Sound Manager, you should not use the value 255. You should change the timbre before playing the sound.
  1846. Stopping Sound Channels
  1847.  
  1848. The Sound Manager allows you both to stop a sound currently in progress in a channel and to remove all pending sound commands from a channel. 
  1849. Note
  1850. If you have started a sound playing by using the SndStartFilePlay function, then you can stop play by using the SndStopFilePlay function. See “Managing an Asynchronous Play From Disk” on page 2-52 for more details.u
  1851. To cause the Sound Manager to stop playing the sound in progress, send the quietCmd command. Here’s an example:
  1852. mySndCmd.cmd := quietCmd;                                                    {the command is quietCmd}
  1853. mySndCmd.param1 := 0;                                                    {unused}
  1854. mySndCmd.param2 := 0;                                                    {unused}
  1855.  
  1856. {stop the sound now playing}
  1857. myErr := SndDoImmediate(mySndChan, mySndCmd, FALSE);
  1858. To bypass the command queue, you should issue quietCmd by using SndDoImmediate. Any sound commands that are already in the sound channel remain there, however, and further sound commands can be queued in that channel.
  1859. If you wish to flush a sound channel without disturbing any sounds already in progress, issue the flushCmd command. Here’s an example:
  1860. mySndCmd.cmd := flushCmd;                                                    {the command is flushCmd}
  1861. mySndCmd.param1 := 0;                                                    {unused}
  1862. mySndCmd.param2 := 0;                                                    {unused}
  1863.  
  1864. {flush the channel}
  1865. myErr := SndDoImmediate(mySndChan, mySndCmd, FALSE);
  1866. If you want to stop all sound production by a particular sound channel immediately, you should issue a flushCmd command and then a quietCmd command. If you issue only a flushCmd command, the sound currently playing is not stopped. If you issue only a quietCmd command, the Sound Manager stops the current sound but continues with any other queued commands. (By calling flushCmd before quietCmd, you ensure that no other queued commands are processed.)
  1867. Note
  1868. The Sound Manager sends a quietCmd command when your application calls the SndDisposeChannel function. The quietCmd command is preceded by a flushCmd command if the quietNow parameter is TRUE.u 
  1869. Pausing and Restarting Sound Channels
  1870.  
  1871. If you want to pause command processing in a particular channel, you can use either of two sound commands, waitCmd or pauseCmd.
  1872. Note
  1873. If you have started a sound playing by using the SndStartFilePlay function, then you can pause and resume play by using the SndPauseFilePlay function. See “Managing an Asynchronous Play From Disk” on page 2-52 for more details.u
  1874. The waitCmd command suspends all processing in a channel for a specified number of half-milliseconds. Here’s an example:
  1875. mySndCmd.cmd := waitCmd;                                                    {the command is waitCmd}
  1876. mySndCmd.param1 := 2000;                                                    {1-second wait duration}
  1877. mySndCmd.param2 := 0;                                                    {unused}
  1878.  
  1879. {pause the channel}
  1880. myErr := SndDoImmediate(mySndChan, mySndCmd, FALSE);
  1881. To pause the processing of commands in a sound channel for an unspecified duration, use the pauseCmd command. Unlike waitCmd, pauseCmd suspends processing for an undetermined amount of time. Processing does not resume until the Sound Manager receives a resumeCmd command for the specified channel.
  1882. To issue waitCmd or pauseCmd, you can use either SndDoImmediate or SndDoCommand, depending on whether you want the suspension of sound channel processing to begin immediately or when the Sound Manager reaches that command in the normal course of reading commands from a sound channel. The resumeCmd command, which is simply the opposite of pauseCmd, should be issued by using SndDoImmediate. Neither waitCmd nor pauseCmd stops any sound that is currently playing; these commands simply stop further processing of commands queued in the sound channel.
  1883. Note
  1884. If no other commands are pending in the sound channel after a resumeCmd command, the Sound Manager sends an emptyCmd command. The emptyCmd command is sent only by the Sound Manager and should not be issued by your application.u 
  1885. Synchronizing Sound Channels
  1886.  
  1887. You can synchronize several different sound channels by issuing syncCmd commands. The param1 field of the sound command contains a count, and the param2 field contains an arbitrary identifier. The Sound Manager keeps track of the count for each channel being synchronized. When the Sound Manager receives a syncCmd command for a certain channel, it decrements the count for each channel having the given identifier, including the newly synchronized channel. Command processing resumes on a channel when the count becomes 0. Thus, if you know how many channels you need to synchronize, you can synchronize them all by arranging for all of their counts to become zero simultaneously. Listing 2-7 illustrates the use of the syncCmd command.
  1888. Listing 2-7    Adding a channel to a group of channels to be synchronized
  1889.  
  1890. PROCEDURE MySync1Chan (chan: SndChannelPtr; count: Integer;
  1891.                                  identifier: LongInt);
  1892. VAR
  1893.     mySndCmd:                 SndCommand;                        {a sound command}
  1894.     myErr:                 OSErr;
  1895. BEGIN
  1896.     WITH mySndCmd DO
  1897.     BEGIN
  1898.         cmd := syncCmd;                                    {the command is syncCmd}
  1899.         param1 := count;
  1900.         param2 := identifier;                                    {ID of group to be synchronized}
  1901.     END;
  1902.     myErr := SndDoImmediate(chan, mySndCmd);
  1903.     IF myErr <> noErr THEN
  1904.         DoError(myErr);
  1905. END;
  1906. For example, to synchronize three channels, first create the channels and then call the MySync1Chan procedure defined in Listing 2-7 for the first channel with a count equal to 4, for the second channel with a count equal to 3, and for the third channel with a count equal to 2, using the same arbitrary identifier for each call to MySync1Chan. Then fill all channels with appropriate sound commands. (For example, you might send commands that will cause the same sequence of notes to be produced on all three synchronized channels.) Finally, call the MySync1Chan procedure one final time, passing any of the three channels and a count of 1. By that time, all of the other channels will have counts of 1, and all counts will become 0 simultaneously, thus initiating synchronized play.
  1907. Note
  1908. The syncCmd command is intended to make it easy to synchronize sound channels. You can use the syncCmd command to start multiple channels of sampled sound playing simultaneously, but if you require precise synchronization of sampled-sound channels, you might achieve better results with the Time Manager, which is described in Inside Macintosh: Processes.u 
  1909. Managing Sound Volumes
  1910.  
  1911. Versions of the Sound Manager prior to 3.0 allow you to set only one volume level, which applies to all sounds produced by the audio hardware. The Sound Manager versions 3.0 and later provide greatly improved control over the volumes of the sounds you ask it to create. You can use new facilities to
  1912. n    set the volumes of the left and right channels of sound independently of each other
  1913. n    set the volume of the system alert sound
  1914. n    set the default volume of a particular sound output device
  1915. You can set the system alert sound volume to a different level than that of any other sounds you produce. For example, you can set the system alert sound to play at a lower volume than other sounds. This would allow a user to hear QuickTime movies at full volume and to hear system alert sounds at a lower volume.
  1916. You can use the volumeCmd and getVolumeCmd sound commands to set and get the right and left volumes of sound. You specify a channel’s volume with 16-bit value, where 0 represents no volume and hexadecimal $0100 represents full volume. The Sound Manager defines constants for silence and full volume.
  1917. CONST
  1918.     kFullVolume                                        = $0100;
  1919.     kNoVolume                                        = 0;
  1920. The volumeCmd sound command expects the right and left volumes to be encoded as the high word and low word, respectively, of param2. For example, to set the left channel to half volume and the right channel to full volume, you pass the value $01000080 in param2, as illustrated in Listing 2-8.
  1921. Listing 2-8    Setting left and right volumes
  1922.  
  1923. FUNCTION MySetVolume (chan: SndChannelPtr): OSErr;
  1924. VAR
  1925.     mySndCmd:                    SndCommand;
  1926.     myRightVol:                    Integer;
  1927.     myLeftVol:                    Integer;
  1928.     myErr:                    OSErr;
  1929. BEGIN
  1930.     myRightVol := kFullVolume;
  1931.     myLeftVol := kFullVolume DIV 2;
  1932.     mySndCmd.cmd := volumeCmd;
  1933.     mySndCmd .param1 := 0;                                                {unused with volumeCmd}
  1934.     mySndCmd.param2 := BSL(myRightVol, 16) + myLeftVol;
  1935.     myErr := SndDoImmediate(chan, mySndCmd);
  1936.     MySetVolume := myErr;
  1937. END;
  1938. You can also use the volumeCmd sound command to pan a sound from one side to another. For example, to send the output signal entirely to the right channel, pass the value $01000000 in param2. To send the output signal entirely to the left channel, pass the value $00000100 in param2. You can overdrive a channel’s volume by passing volume levels greater than $0100. For example, to play the left channel of a stereo sound at twice full volume while playing the right channel at full volume, pass the value $01000200.
  1939. You can use the GetSysBeepVolume and SetSysBeepVolume functions to get and set the output volume level of the system alert sound. Any calls to the SysBeep procedure use the volume set by the previous call to SetSysBeepVolume. As you’ve learned, this allows you to set a lower volume for the system alert sound than for your other sound output.
  1940. You can use the GetDefaultOutputVolume and SetDefaultOutputVolume functions to set the default output volumes for a particular output device. Each output device has its own current volume setting and its own default setting. If the user changes the output device (using the Sound control panel), the newly selected device will use its own default volume level.
  1941. Obtaining Sound-Related Information
  1942.  
  1943. Developments in the sound hardware available on Macintosh computers and in the Sound Manager routines that allow you to drive that hardware have made it imperative that your application pay close attention to the sound-related features of the operating environment. For example, some Macintosh computers do not have the sound input hardware necessary to allow sound recording. Similarly, some other Macintosh computers are not able to record sounds and play sounds simultaneously. Before taking advantage of a sound-related feature that is not available on all Macintosh computers, you should check to make sure that the target machine provides the features you need.
  1944. To make appropriate decisions about the sound you want to produce, you might need to know some or all of the following types of information:
  1945. n    whether a machine can produce stereophonic sounds
  1946. n    what version of the Sound Manager is available
  1947. n    whether a machine can play multiple channels of sound, and whether it can take advantage of the enhanced Sound Manager’s play-from-disk capabilities
  1948. n    whether a sound playing from disk is active or paused
  1949. n    how many channels of sound are currently open
  1950. n    whether the system beep has been disabled
  1951. The following sections describe how to use the Gestalt function and Sound Manager routines to determine these types of information.
  1952. Obtaining Information About Available Sound Features
  1953.  
  1954. You can use the Gestalt function to obtain information about a number of hardware- and software-related sound features. For instance, you can use Gestalt to determine whether a machine can produce stereophonic sounds and whether it can mix both left and right channels of sound on the internal speaker. Many applications don’t need to call Gestalt to get this kind of information if they rely on the Sound Manager’s ability to produce reasonable sounding output on whatever audio hardware is available. Other applications, however, do need to use Gestalt to get this information if they depend on specific hardware or software features that are not available on all Macintosh computers.
  1955. To get sound-related information from Gestalt, pass it the gestaltSoundAttr selector.
  1956. CONST
  1957.     gestaltSoundAttr                                = 'snd ';                {sound attributes}
  1958. If Gestalt returns successfully, it passes back to your application a 32-bit value that represents a bit pattern. The following constants define the bits currently set or cleared by Gestalt:
  1959. CONST
  1960.     gestaltStereoCapability                                    = 0;            {built-in hw can play stereo sounds}
  1961.     gestaltStereoMixing                                    = 1;            {built-in hw mixes stereo to mono}
  1962.     gestaltSoundIOMgrPresent                                    = 3;            {sound input routines available}
  1963.     gestaltBuiltInSoundInput                                    = 4;            {built-in input hw available}
  1964.     gestaltHasSoundInputDevice                                    = 5;            {sound input device available}
  1965.     gestaltPlayAndRecord                                    = 6;            {built-in hw can play while recording}
  1966.     gestalt16BitSoundIO                                     = 7;            {built-in hw can handle 16-bit data}
  1967.     gestaltStereoInput                                     = 8;            {built-in hw can record stereo sounds}
  1968.     gestaltLineLevelInput                                     = 9;            {built-in input hw needs line level}
  1969.     gestaltSndPlayDoubleBuffer                                    = 10;            {play from disk routines available}
  1970.     gestaltMultiChannels                                    = 11;            {multiple channels of sound supported}
  1971.     gestalt16BitAudioSupport                                     = 12;            {16-bit audio data supported}
  1972. If the bit gestaltStereoCapability is TRUE, the built-in hardware can play stereo sounds. The bit gestaltStereoMixing indicates that the sound hardware of the machine mixes both left and right channels of stereo sound into a single audio signal for the internal speaker. Listing 2-9 demonstrates the use of the Gestalt function to determine if a machine can play stereo sounds.
  1973. Listing 2-9    Determining if stereo capability is available
  1974.  
  1975. FUNCTION MyHasStereo: Boolean;
  1976. VAR
  1977.     myFeature:                    LongInt;
  1978.     myErr:                    OSErr;
  1979. BEGIN
  1980.     myErr := Gestalt(gestaltSoundAttr, myFeature);
  1981.     IF myErr = noErr THEN                                    {test stereo capability bit}
  1982.         MyHasStereo := BTst(myFeature, gestaltStereoCapability)
  1983.     ELSE
  1984.         MyHasStereo := FALSE;                                {no sound features available}
  1985. END;
  1986. As shown in the chapter “Introduction to Sound on the Macintosh,” you can determine whether your application can record by testing the gestaltHasSoundInputDevice bit. To determine whether a built-in sound input device is available, you can test the gestaltBuiltInSoundInput bit. The gestaltSoundIOMgrPresent bit indicates whether the sound input routines are available. Because the gestaltHasSoundInputDevice bit is not set if the routines are not available, only sound input device drivers should need to use the gestaltSoundIOMgrPresent bit.
  1987. For a complete description of the response bits set by Gestalt, see “Gestalt Selector and Response Bits” beginning on page 2-90.
  1988. Obtaining Version Information
  1989.  
  1990. The Sound Manager provides functions that allow you to determine the version numbers both of the Sound Manager itself and of the MACE compression and expansion routines. Generally, you should avoid trying to determine which features or routines are present by reading a version number. Usually, the Gestalt function (discussed in the previous section) provides a better way to find out if some set of features, such as sound input capability, is available. In some cases, however, you can use these version routines to overcome current limitations of the information returned by Gestalt.
  1991. Both of these functions return a value of type NumVersion that contains the same information as the first 4 bytes of a resource of type 'vers'. The first and second bytes contain the major and minor version numbers, respectively; the third and fourth bytes contain the release level and the stage of the release level. For most purposes, the major and minor release version numbers are sufficient to identify the version. (See the chapter “Finder Interface” of Inside Macintosh: Macintosh Toolbox Essentials for a complete discussion of the format of 'vers' resources.)
  1992. You can use the SndSoundManagerVersion function to determine which version of the Sound Manager is present. Listing 2-10 shows how to determine if the enhanced Sound Manager is available.
  1993. Listing 2-10    Determining if the enhanced Sound Manager is present
  1994.  
  1995. FUNCTION MyHasEnhancedSoundManager: Boolean;
  1996. VAR
  1997.     myVersion:                    NumVersion;
  1998. BEGIN
  1999.     IF MyTrapAvailable(_SoundDispatch) THEN
  2000.     BEGIN
  2001.         myVersion := SndSoundManagerVersion;
  2002.         MyHasEnhancedSoundManager := myVersion.majorRev >= 2;
  2003.     END
  2004.     ELSE
  2005.         MyHasEnhancedSoundManager := FALSE
  2006. END;
  2007. The MyHasEnhancedSoundManager function defined in Listing 2-10 relies on the MyTrapAvailable function, which is an application-defined routine provided in Inside Macintosh: Operating System Utilities. If the _SoundDispatch trap is not available, the SndSoundManagerVersion function is not available either, in which case the enhanced Sound Manager is certainly not available.
  2008. You can use the MACEVersion function to determine the version number of the available MACE routines (for example, Comp3to1).
  2009. Testing for Multichannel Sound and Play-From-Disk Capabilities
  2010.  
  2011. The ability to play multiple channels of sound simultaneously and the ability to initiate plays from disk were first introduced with the enhanced Sound Manager. Even with the enhanced Sound Manager, however, these capabilities are present only on computers equipped with suitable sound output hardware (such as an Apple Sound Chip). Sound Manager version 3.0 defines 2 additional bits in the Gestalt response parameter that allow you to test directly for these two capabilities.
  2012. CONST
  2013.     gestaltSndPlayDoubleBuffer                                        = 10;        {play from disk routines available}
  2014.     gestaltMultiChannels                                        = 11;        {multiple channels of sound supported}
  2015. Ideally, it should be sufficient to test directly, using Gestalt, for either multichannel sound capability or play-from-disk capability. If your application happens to be running under the enhanced Sound Manager, however, the two new response bits are not defined. In that case, you’ll need to test also whether the Apple Sound Chip is available, because multichannel sound and play from disk are supported by the enhanced Sound Manager only if the Apple Sound Chip is available. To test for the presence of the Apple Sound Chip, you can use the Gestalt function with the gestaltHardwareAttr selector and the gestaltHasASC bit. Listing 2-11 combines these two tests into a single routine that returns TRUE if the computer supports multichannel sound.
  2016. Listing 2-11    Testing for multichannel play capability
  2017.  
  2018. FUNCTION MyCanPlayMultiChannels: Boolean;
  2019. VAR
  2020.     myResponse:                    LongInt;
  2021.     myResult:                    Boolean;
  2022.     myErr:                    OSErr;
  2023.     myVersion:                    NumVersion;
  2024. BEGIN
  2025.     myResult := FALSE;
  2026.     myVersion := SndSoundManagerVersion;
  2027.     myErr := Gestalt(gestaltSoundAttr, myResponse);
  2028.     IF myVersion.majorRev >= 3 THEN
  2029.         IF (myErr = noErr) AND (BTst(myResponse, gestaltMultiChannels)) THEN
  2030.             myResult := TRUE
  2031.     ELSE
  2032.         BEGIN
  2033.             myErr := Gestalt(gestaltHardwareAttr, myResponse);
  2034.             IF (myErr = noErr) AND (BTst(myResponse, gestaltHasASC)) THEN
  2035.                 myResult := TRUE
  2036.         END;
  2037.     MyCanPlayMultiChannels := myResult;
  2038. END;
  2039. The function MyCanPlayMultiChannels first tries to get the desired information by calling the Gestalt function with the gestaltSoundAttr selector. If Gestalt returns successfully and the gestaltMultiChannels bit is set in the response parameter, then multichannel play capability is present. Notice that the multichannel bit is checked only if the version of the Sound Manager is 3.0 or greater. If the version is not at least 3.0, then MyCanPlayMultiChannels calls the Gestalt function with the gestaltHardwareAttr selector. If the computer contains the Apple Sound Chip, then again multichannel play capability is present.
  2040. Note
  2041. The gestaltHasASC bit is set only on machines that contain an Apple Sound Chip. You should test for the presence of the Apple Sound Chip only in the circumstances described above.u
  2042. You could write a similar function to test for the ability to initiate a play from disk. Listing 2-12 shows an example.
  2043. Listing 2-12    Testing for play-from-disk capability
  2044.  
  2045. FUNCTION HasPlayFromDisk: Boolean;
  2046. VAR
  2047.     myResponse:                    LongInt;
  2048.     myResult:                    Boolean;
  2049.     myErr:                    OSErr;
  2050.     myVersion:                    NumVersion;
  2051. BEGIN
  2052.     myResult := FALSE;
  2053.     myVersion := SndSoundManagerVersion;
  2054.     myErr := Gestalt(gestaltSoundAttr, myResponse);
  2055.     IF myVersion.majorRev >= 3 THEN
  2056.         IF (myErr = noErr) AND 
  2057.                                 (BTst(myResponse, gestaltSndPlayDoubleBuffer)) THEN
  2058.             myResult := TRUE
  2059.     ELSE
  2060.         BEGIN
  2061.             myErr := Gestalt(gestaltHardwareAttr, myResponse);
  2062.             IF (myErr = noErr) AND (BTst(myResponse, gestaltHasASC)) THEN
  2063.                 myResult := TRUE
  2064.         END;
  2065.     HasPlayFromDisk := myResult;
  2066. END;
  2067. Obtaining Information About a Single Sound Channel
  2068.  
  2069. You can use the SndChannelStatus function to obtain information about a single sound channel and about the status of a disk-based playback on that channel, if one exists. For example, you can use SndChannelStatus to determine if a channel is being used for play from disk, how many seconds of the sound have been played, and how many seconds remain to be played.
  2070. One of the parameters required by the SndChannelStatus function is a pointer to a sound channel status record, which you must allocate before calling SndChannelStatus. A sound channel status record has this structure:
  2071. TYPE SCStatus =
  2072. RECORD
  2073.     scStartTime:                                Fixed;                {starting time for play from disk}
  2074.     scEndTime:                                Fixed;                {ending time for play from disk}
  2075.     scCurrentTime:                                Fixed;                {current time for play from disk}
  2076.     scChannelBusy:                                Boolean;                {TRUE if channel is processing cmds}
  2077.     scChannelDisposed:                                Boolean;                {reserved}
  2078.     scChannelPaused:                                Boolean;                {TRUE if channel is paused}
  2079.     scUnused:                                Boolean;                {unused}
  2080.     scChannelAttributes:                                LongInt;                {attributes of this channel}
  2081.     scCPULoad:                                LongInt;                {CPU load for this channel}
  2082. END;
  2083. The scStartTime, scEndTime, and scCurrentTime fields are 0 unless the Sound Manager is currently playing from disk through the specified channel. If a play from disk is occurring, the scStartTime and scEndTime fields reflect the starting and ending points of the play, defined in seconds; the scCurrentTime field indicates the number of seconds between the beginning of the sound on disk and the part of the sound currently being played. The Sound Manager sets the values of the scStartTime and scEndTime fields based on the values you set in an audio selection record. (See page 2-100 for a description of the audio selection record.)
  2084. Note that because the Sound Manager might be playing only a selection of a sound, the scCurrentTime field does not reflect the number of seconds of sound play that have elapsed. To compute the number of seconds of sound play elapsed, you can subtract the value in the scStartTime field from that in the scCurrentTime field. However, because the Sound Manager updates the value of the scCurrentTime field only periodically, you should not rely on the accuracy of its value.
  2085. The scChannelBusy and scChannelPaused fields reflect whether a channel is processing commands and whether a channel is paused, respectively. After issuing a series of sound commands, you can use these fields to determine if the channel has finished processing all of the commands. If both scChannelBusy and scChannelPaused are FALSE, the Sound Manager has processed all of the channel’s commands.
  2086. You can mask out certain values in the scChannelAttributes field to determine how a channel has been initialized.
  2087. CONST
  2088.     initPanMask                    = $0003;                {mask for right/left pan values}
  2089.     initSRateMask                    = $0030;                {mask for sample rate values}
  2090.     initStereoMask                    = $00C0;                {mask for mono/stereo values}
  2091. The scCPULoad field previously reflected the percentage of CPU processing power used by the sound channel. However, this field is obsolete, and you should not rely on its value.
  2092. Listing 2-13 illustrates the use of the SndChannelStatus function. It defines a function that takes a sound channel pointer as a parameter and determines whether a disk-based playback on that channel is paused.
  2093. Listing 2-13    Determining whether a sound channel is paused
  2094.  
  2095. FUNCTION MyChannelIsPaused (chan: SndChannelPtr): Boolean;
  2096. VAR
  2097.     myErr:                    OSErr;
  2098.     mySCStatus:                    SCStatus;
  2099. BEGIN
  2100.     MyChannelIsPaused := FALSE;
  2101.     myErr := SndChannelStatus(chan, Sizeof(SCStatus), @mySCStatus);
  2102.     IF myErr = noErr THEN
  2103.         MyChannelIsPaused := mySCStatus.scChannelPaused;
  2104. END;
  2105. The function defined in Listing 2-13 simply reads the scChannelPaused field to see if the playback is currently paused.
  2106. Note
  2107. In Sound Manager versions earlier than 3.0, pausing a sound channel by issuing a pauseCmd command does not change the scChannelPaused field. The scChannelPaused field is TRUE only if the Sound Manager is executing a disk-based playback on the channel and that playback is paused by the SndPauseFilePlay function. This problem is fixed in Sound Manager versions 3.0 and later.u 
  2108. Obtaining Information About All Sound Channels
  2109.  
  2110. You can use the SndManagerStatus function to determine information about all the sound channels that are currently allocated by all applications. For example, you can use this function to determine how many channels are currently allocated. One of the parameters required by the SndManagerStatus function is a pointer to a Sound Manager status record, which you must allocate before calling SndManagerStatus. A Sound Manager status record has this structure:
  2111. TYPE SMStatus =
  2112. PACKED RECORD
  2113.     smMaxCPULoad:                        Integer;                {maximum load on all channels}
  2114.     smNumChannels:                        Integer;                {number of allocated channels}
  2115.     smCurCPULoad:                        Integer;                {current load on all channels}
  2116. END;
  2117. The smNumChannels field contains the number of sound channels currently allocated. This does not mean that the channels are actually being used, only that they have been created with the SndNewChannel function and not yet disposed.
  2118. The Sound Manager uses information that it returns in the smMaxCPULoad and smCurCPULoad fields to help it determine whether it can allocate a new channel when your application calls the SndNewChannel function. The Sound Manager sets smMaxCPULoad to a default value of 100 at startup time, and the smCurCPULoad field reflects the approximate percentage of CPU processing power currently taken by allocated sound channels.
  2119. sWARNING
  2120. Your application should not reply on the values returned in the smMaxCPULoad and smCurCPULoad fields. To determine if it is safe to allocate a channel, simply try to allocate it with the SndNewChannel function. That function returns the appropriate result code if allocating the channel would put too much of a strain on CPU processing.s
  2121. Listing 2-14 illustrates the use of SndManagerStatus. It defines a function that returns the number of sound channels currently allocated by all applications.
  2122. Listing 2-14    Determining the number of allocated sound channels
  2123.  
  2124. FUNCTION MyGetNumChannels: Integer;
  2125. VAR
  2126.     myErr:                    OSErr;
  2127.     mySMStatus:                    SMStatus;
  2128. BEGIN
  2129.     MyGetNumChannels := 0;
  2130.     myErr := SndManagerStatus (Sizeof(SMStatus), @mySMStatus);
  2131.     IF myErr = noErr THEN
  2132.         MyGetNumChannels := mySMStatus.smNumChannels;
  2133. END;
  2134. Determining and Changing the Status of the System Alert Sound
  2135.  
  2136. The enhanced Sound Manager includes two routines—SndGetSysBeepState and SndSetSysBeepState—that allow you to determine and alter the status of the system alert sound. You might wish to disable the system alert sound if you are playing sound and need to ensure that the sound you are playing is not interrupted. Currently, two states are defined:
  2137. CONST
  2138.     sysBeepDisable                            = $0000;                {system alert sound disabled}
  2139.     sysBeepEnable                            = $0001;                {system alert sound enabled}
  2140. You can determine the status of the system alert sound like this:
  2141. SndGetSysBeepState(currentState);
  2142. And you can disable the system alert sound like this:
  2143. myErr := SndSetSysBeepState(sysBeepDisable);
  2144. When the system alert sound is disabled, the Sound Manager effectively ignores all calls to the SysBeep procedure. No sound is created and the menu bar does not flash. Also, no resources are loaded into memory.
  2145. Note
  2146. Even when the system alert sound is enabled, it’s possible that the system alert sound will not play; for example, the speaker volume might be set to 0, or playing the requested system alert sound might require too much CPU time. In such a case, the menu bar flashes.u
  2147. By default, the system alert sound is enabled. If you disable the system alert sound so that your application can play a sound without being interrupted, be sure to enable the sound when your application receives a suspend event or when the user quits your application.
  2148. Playing Notes
  2149.  
  2150. You can play notes one at a time by using the SndDoCommand or SndDoImmediate function to issue freqDurationCmd sound commands. A sound plays for a specified duration at a specified frequency. You can play sounds defined by any of the three sound data formats. If you play wave-table data or sampled-sound data, then a voice must previously have been installed in the channel. (See “Installing Voices Into Channels” on page 2-43 for instructions on installing wave tables and sampled sounds as voices.)
  2151. You can also play notes by issuing the freqCmd command, which is identical to the freqDurationCmd command, except that no duration is specified when you issue freqCmd. 
  2152. Note
  2153. A freqDurationCmd command might in certain cases continue playing until another command is available in the sound channel. Therefore, to play a single note for a specified duration, you should issue freqDurationCmd followed immediately by quietCmd. See “Stopping Sound Channels” on page 2-28 for further details on quietCmd.u 
  2154. The structure of a freqDurationCmd command is slightly different from that of most other sound commands. The param1 field contains the duration of the sound, specified in half-milliseconds. A value of 2000 represents a duration of 1 second. The maximum duration is 32,767, or about 16 seconds, in Sound Manager versions 2.0 and earlier; the maximum duration in Sound Manager version 3.0 and later is 65,536, or about 32 seconds. The param2 field specifies the frequency of the sound. The frequency is specified as a MIDI note value (that is, a value defined by the established MIDI standard). Listing 2-15 uses the freqDurationCmd command in a way that ensures the sound stops after the specified duration.
  2155. Listing 2-15    Using the freqDurationCmd command
  2156.  
  2157. PROCEDURE MyPlayFrequencyOnce (mySndChan: SndChannelPtr;
  2158.                                             myMIDIValue: Integer;
  2159.                                             milliseconds: Integer);
  2160. CONST
  2161.     kNoWait = TRUE;                                            {add now to full queue?}
  2162. VAR
  2163.     mySndCmd:                SndCommand;                            {a sound command}
  2164.     myErr:                OSErr;
  2165. BEGIN
  2166.     {Start the sound playing.}
  2167.     WITH mySndCmd DO
  2168.     BEGIN
  2169.         cmd := freqDurationCmd;                                        {play for period of time}
  2170.         param1 := milliseconds * 2;                                        {half-milliseconds}
  2171.         param2 := myMIDIValue;                                        {MIDI value to play}
  2172.     END;
  2173.     myErr := SndDoCommand(mySndChan, mySndCmd, NOT kNoWait);
  2174.     IF myErr <> noErr THEN
  2175.         DoError(myErr)
  2176.     ELSE
  2177.     BEGIN                                             {ensure that sound stops}
  2178.         WITH mySndCmd DO
  2179.         BEGIN
  2180.             cmd := quietCmd;                                    {stop playing sound}
  2181.             param1 := 0;                                    {unused with quietCmd}
  2182.             param2 := 0;                                    {unused with quietCmd}
  2183.         END;
  2184.         myErr := SndDoCommand(mySndChan, mySndCmd, NOT kNoWait);
  2185.         IF myErr <> noErr THEN
  2186.             DoError(myErr);
  2187.     END;
  2188. END;
  2189. Table 2-2 shows the decimal values that can be sent with a freqDurationCmd or freqCmd command. Middle C is represented by a value of 60 and is defined by a special Sound Manager constant.
  2190. CONST
  2191.     kMiddleC                    = 60;                {MIDI note value for middle C}
  2192. Other specifiable frequencies correspond to MIDI note values.
  2193. Table 2-2    Frequencies expressed as MIDI note values
  2194.     A    A#    B    C    C#    D    D#    E    F    F#    G    G#    
  2195. Octave 1                0    1    2    3    4    5    6    7    8    
  2196. Octave 2    9    10    11    12    13    14    15    16    17    18    19    20    
  2197. Octave 3    21    22    23    24    25    26    27    28    29    30    31    32    
  2198. Octave 4    33    34    35    36    37    38    39    40    41    42    43    44    
  2199. Octave 5    45    46    47    48    49    50    51    52    53    54    55    56    
  2200. Octave 6    57    58    59    60    61    62    63    64    65    66    67    68    
  2201. Octave 7    69    70    71    72    73    74    75    76    77    78    79    80    
  2202. Octave 8    81    82    83    84    85    86    87    88    89    90    91    92    
  2203. Octave 9    93    94    95    96    97    98    99    100    101    102    103    104    
  2204. Octave 10    105    106    107    108    109    110    111    112    113    114    115     116    
  2205. Octave 11    117    118    119    120    121    122    123    124    125    126    127        
  2206.  
  2207. You can play square-wave and wave-table data at these frequencies only. If you are playing a sampled sound, however, you can modify the sampleRate field of the sound header to play a sound at an arbitrary frequency. To do so, use the following formula:
  2208. new sample rate = (new frequency / original frequency) * original sample rate
  2209. where the new and original frequencies are measured in hertz. To convert a MIDI value to hertz for use in this formula, note that middle C is defined as 261.625 Hz and that the ratio between the frequencies of consecutive MIDI values equals the twelfth root of 2, defined by the constant twelfthRootTwo.
  2210. CONST
  2211.     twelfthRootTwo                                = 1.05946309434;
  2212. IMPORTANT
  2213. When calculating with numbers of type Fixed, pay attention to possible overflows. The maximum value of a number of type Fixed is 65,535.0. As a result, some sample rates and pitches cannot be specified. Sound Manager version 3.0 fixes these overflow problems.s
  2214. You can rest a channel for a specified duration by issuing a restCmd command. The duration, specified in half-milliseconds, is passed in the param1 field of the sound command.
  2215. Installing Voices Into Channels   
  2216.  
  2217. You can play frequencies defined by any of the three sound data types. By playing a frequency defined by wave-table or sampled-sound data, you can achieve a different sound than by playing that same frequency using square-wave data. For example, you might wish to play the sound of a dog’s barking at a variety of frequencies. To do that, however, you need to install a voice of the barking into the sound channel to which you want to send freqCmd or freqDurationCmd commands.
  2218. You can install a wave table into a channel as a voice by issuing the waveTableCmd command. The param1 field of the sound command specifies the length of the wave table, and the param2 field is a pointer to the wave-table data itself. Note that the Sound Manager resamples the wave table so that it is exactly 512 bytes long. 
  2219. You can install a sampled sound into a channel as a voice by issuing the soundCmd command. You can either issue this command from your application or put it into an 'snd ' resource. If your application sends this command, param2 is a pointer to the sampled sound locked in memory. If soundCmd is contained within an 'snd ' resource, the high bit of the command must be set. To use a sampled-sound 'snd ' as a voice, first obtain a pointer to the sampled sound header locked in memory. Then pass this pointer in param2 of a soundCmd command. After using the sound, your application is expected to unlock this resource and allow it to be purged.
  2220. Listing 2-16 demonstrates how you can use the soundCmd command to install a sampled sound in memory as a voice in a channel.
  2221. Listing 2-16    Installing a sampled sound as a voice in a channel
  2222.  
  2223. FUNCTION MyInstallSampledVoice (mySndHandle: Handle;
  2224.                                             mySndChan: SndChannelPtr): OSErr;
  2225. VAR
  2226.     mySndCmd:                         SndCommand;                            {a sound command}
  2227.     mySndHeader:                         SoundHeaderPtr;                            {sound header from resource}
  2228. BEGIN
  2229.                                                         {get pointer to sound header}
  2230.     mySndHeader := MyGetSoundHeader(mySndHandle);
  2231.     WITH mySndCmd DO
  2232.     BEGIN
  2233.         cmd := soundCmd;                                                {install sampled voice}
  2234.         param1 := 0;                                                {ignored with soundCmd}
  2235.         param2 := LongInt(mySndHeader);                                                {store sound header location}
  2236.     END;
  2237.     IF mySndHeader = NIL THEN                                                    {check for defective handle}
  2238.         MyInstallSampledVoice := badFormat
  2239.     ELSE                                                    {install sound as voice}
  2240.         MyInstallSampledVoice := SndDoImmediate(mySndChan, mySndCmd);
  2241. END;
  2242. Listing 2-16 relies on the MyGetSoundHeader function to obtain a pointer to the sound header within the sound handle. That function is defined in “Obtaining a Pointer to a Sound Header” on page 2-57 and returns NIL if the sound handle does not include a sound header. Note that the MyGetSoundHeader function locks the sound handle in memory so that the pointer to the sound header remains valid. When you are done with the sound channel in which you have installed the sampled sound, you should unlock the sound handle and make it purgeable so that it does not waste memory. 
  2243. Looping a Sound Indefinitely
  2244.  
  2245. If you install a sampled sound as a voice in a channel and then play the sound using a freqCmd or freqDurationCmd command that lasts longer than the sound, the sound will ordinarily stop before the end of the time specified by the freqCmd or freqDurationCmd command. Sometimes, however, this might not be what you’d like to have happen. For example, you might have recorded the sound of a violin playing and then stored that sound in a resource so that you could play the sound of a violin at a number of different frequencies. Although you could record the sound so that it is long enough to continue playing through the longest freqCmd or freqDurationCmd command that your application might require, this might not be practical. Fortunately, the Sound Manager provides a mechanism that allows you to repeat sections of sampled sound after the sound has finished playing once completely.
  2246. When you use the freqDurationCmd command with a sampled sound as the voice, freqDurationCmd starts at the beginning of the sampled sound. If necessary to achieve the desired duration of sound, the command replays that part of the sound that is between the loop points specified in the sampled sound header. Note that any sound preceding or following the loop points will not be replayed. There must be an ending point for the loop specified in the header in order for freqDurationCmd to work properly.
  2247. Listing 2-17    Looping an entire sampled sound
  2248.  
  2249. PROCEDURE MyDoLoopEntireSound (sndHandle: Handle);
  2250. VAR
  2251.     mySndHeader:                     SoundHeaderPtr;                            {sound header from resource}
  2252.     myTotalBytes:                     LongInt;                            {bytes of data to loop}
  2253. BEGIN
  2254.     mySndHeader := MyGetSoundHeader(sndHandle);
  2255.     IF mySndHeader <> NIL THEN
  2256.     BEGIN                                                {compute bytes of sound data}
  2257.         CASE mySndHeader^.encode OF
  2258.             stdSH:                                         {standard sound header}
  2259.                 WITH mySndHeader^ DO
  2260.                     myTotalBytes := mySndHeader^.length;
  2261.             extSH:                                         {extended sound header}
  2262.                 WITH ExtSoundHeaderPtr(mySndHeader)^ DO
  2263.                     myTotalBytes := numChannels * numFrames * (sampleSize DIV 8);
  2264.             cmpSH:                                         {compressed sound header}
  2265.                 WITH CmpSoundHeaderPtr(mySndHeader)^ DO
  2266.                     myTotalBytes := numChannels * numFrames * (sampleSize DIV 8);
  2267.         END;
  2268.         WITH mySndHeader^ DO
  2269.         BEGIN                                            {set loop points}
  2270.             loopStart := 0;                                        {start with first byte}
  2271.             loopEnd := myTotalBytes - 1;                                        {end with last byte}
  2272.         END;
  2273.     END;
  2274. END;
  2275. Listing 2-17 uses the MyGetSoundHeader function defined in “Obtaining a Pointer to a Sound Header” on page 2-57. Note that the formula for computing the length of a sound depends on the type of sound header. Also, while the formula is the same for both an extended and a compressed sound header, you must write code that differentiates between the two types of sound headers because the sampleSize field is not stored in the same location in both sound headers.
  2276. Playing Sounds Asynchronously 
  2277.  
  2278. The Sound Manager currently allows you to play sounds asynchronously only if you allocate sound channels yourself, using techniques described in “Managing Sound Channels” on page 2-19. But if you use such a technique, your application will need to dispose of a sound channel whenever the application finishes playing a sound. In addition, your application might need to release a sound resource that you played on a sound channel.
  2279. To avoid the problem of not knowing when to dispose of a sound channel playing a sound asynchronously, your application could simply allocate a single sound channel when it starts up (or receives a resume event) and dispose of the channel when the user quits (or the application receives a suspend event). However, this solution will not work if you need to release a resource when a sound finishes playing. Also, you might not want to keep a sound channel allocated when you are not using it. For instance, you might want to use the memory taken up by a sound channel for other tasks when no sound is playing.
  2280. Your application could call the SndChannelStatus function once each time through its main event loop to determine if a channel is still making sound. When the scBusy field of the sound channel status record becomes FALSE, your application could then dispose of the channel. This technique is easy, but calling SndChannelStatus frequently uses up processing time unnecessarily.
  2281. The Sound Manager provides other mechanisms that allow your application to find out when a sound finishes playing, so that your application can arrange to dispose of sound channels no longer being used and of other data (such as a sound resource) that you no longer need after disposing of a channel. If you are using the SndPlay function or low-level commands to play sound in a channel, then you can use callback procedures. If you are using the SndStartFilePlay function to play sound in a channel, then you can use completion routines. The following sections illustrate how to use callback procedures and completion routines.
  2282. Note
  2283. Callback procedures are a form of completion routine. However, for clarity, this section uses the terminology “completion routine” only for the routines associated with the SndStartFilePlay function.u
  2284. Using Callback Procedures
  2285.  
  2286. This section shows how you can use callback procedures to play one sound asynchronously at a given time. “Managing Multiple Sound Channels” on page 2-53 expands the techniques in this section to show how you can play several asynchronous sounds simultaneously.
  2287. The SndNewChannel function allows you to associate a callback procedure with a sound channel. For example, the following code opens a new sound channel for which memory has already been allocated and associates it with the callback procedure MyCallBack:
  2288. myErr := SndNewChannel(gSndChan, sampledSynth, initMono, @MyCallback);
  2289. After filling a channel created by SndNewChannel with various commands to create sound, you can then issue a callBackCmd command to the channel. When the Sound Manager encounters a callBackCmd command, it executes your callback procedure. Thus, by placing the callBackCmd command last in a channel, you can ensure that the Sound Manager executes your callback procedure only after it has processed all of the channel’s other sound commands.
  2290. Note
  2291. Be sure to issue callBackCmd commands with the SndDoCommand function and not the SndDoImmediate function. If you issue a callBackCmd command with SndDoImmediate, your callback procedure might be called before other sound commands you have issued finish executing.u
  2292. A callback procedure has the following syntax:
  2293. PROCEDURE MyCallBack (chan: SndChannelPtr; cmd: SndCommand);
  2294. Because the callback procedure executes at interrupt time, it cannot access its application global variables unless the application’s A5 world is set correctly. (For more information on the A5 world, see the chapter “Memory Management Utilities” in Inside Macintosh: Memory.) When called, the callback procedure is passed two parameters: a pointer to the sound channel that received the callBackCmd command and the sound command that caused the callback procedure to be called. Applications can use param1 or param2 of the sound command as flags to pass information or instructions to the callback procedure. If your callback procedure is to use your application’s global data storage, it must first reset A5 to your application’s A5 and then restore it on exit. For example, Listing 2-18 illustrates how to set up a callBackCmd command that contains the required A5 information in the param2 field. The MyInstallCallback function defined there must be called at a time when your application’s A5 world is known to be valid.
  2295. Listing 2-18    Issuing a callback command
  2296.  
  2297. FUNCTION MyInstallCallback (mySndChan: SndChannelPtr): OSErr;
  2298. CONST
  2299.     kWaitIfFull = TRUE;                                        {wait for room in queue}
  2300. VAR
  2301.     mySndCmd:                SndCommand;                        {a sound command}
  2302. BEGIN
  2303.     WITH mySndCmd DO
  2304.     BEGIN
  2305.         cmd := callBackCmd;                                    {install the callback command}
  2306.         param1 := kSoundComplete;                                    {last command for this channel}
  2307.         param2 := SetCurrentA5;                                    {pass the callback the A5}
  2308.     END;
  2309.     MyInstallCallback := SndDoCommand(mySndChan, mySndCmd, kWaitIfFull);
  2310. END;
  2311. In this function, kSoundComplete is an application-defined constant that indicates that the requested sound has finished playing. You could define it like this:
  2312. CONST
  2313.     kSoundComplete                                 = 1;            {sound is done playing}
  2314. Because param2 of a sound command is a long integer, Listing 2-18 uses it to pass the application’s A5 to the callback procedure. That allows the callback procedure to gain access to the application’s A5 world.
  2315. Note
  2316. You can also pass information to a callback routine in the userInfo field of the sound channel.u
  2317. The sample callback procedure defined in Listing 2-19 can thus set A5 to access the application’s global variables.
  2318. Listing 2-19    Defining a callback procedure
  2319.  
  2320. PROCEDURE MyCallback (theChan: SndChannelPtr; theCmd: SndCommand);
  2321. VAR
  2322.     myA5:                    LongInt;
  2323. BEGIN
  2324.     IF theCmd.param1 = kSoundComplete THEN
  2325.     BEGIN
  2326.         myA5 := SetA5(theCmd.param2);                                            {set my A5}
  2327.         gCallbackPerformed := TRUE;                                            {set a global flag}
  2328.         myA5 := SetA5(myA5);                                            {restore the original A5}
  2329.     END;
  2330. END;
  2331. sWARNING
  2332. Callback procedures are called at interrupt time and therefore must not attempt to allocate, move, or dispose of memory, dereference an unlocked handle, or call other routines that do so. Also, assembly-language programmers should note that a callback procedure is a Pascal procedure and must preserve all registers other than A0–A1 and D0–D2.s
  2333. Callback procedures cannot dispose of channels themselves, because that involves disposing of memory. To circumvent this restriction, the callback procedure in Listing 2-19 simply sets the value of a global flag variable that your application defines. Then, once each time through its main event loop, your application must call a routine that checks to see if the flag is set. If the flag is set, the routine should dispose of the channel, release any other memory allocated specifically for use in the channel, and reset the flag variable. Listing 2-20 defines such a routine. Your application should call it once each time through its main event loop.
  2334. Listing 2-20    Checking whether a callback procedure has executed
  2335.  
  2336. PROCEDURE MyCheckSndChan;
  2337. CONST
  2338.     kQuietNow = TRUE;                                            {need to quiet channel?}
  2339. VAR
  2340.     myErr:            OSErr;
  2341. BEGIN
  2342.     IF gCallbackPerformed THEN                                            {check global flag}
  2343.     BEGIN                                            {channel is done}
  2344.         gCallbackPerformed := FALSE;                                        {reset global flag}
  2345.         IF gSndChan^.userInfo <> 0 THEN
  2346.         BEGIN                                         {release sound data}
  2347.             HUnlock(Handle(gSndChan^.userInfo));
  2348.             HPurge(Handle(gSndChan^.userInfo));
  2349.         END;
  2350.         myErr := MyDisposeSndChannel(gSndChan, kQuietNow);
  2351.         gSndChan := NIL;                                        {set pointer to NIL}
  2352.     END;
  2353. END;
  2354. The MyCheckSndChan procedure defined in Listing 2-20 checks the userInfo field of the sound channel to see if it contains the address of a handle. Thus, if you would like the MyCheckSndChan procedure to release memory associated with a sound handle, you need only put the address of the handle in the userInfo field of the sound channel. (If you do not want the MyCheckSndChan procedure to release memory associated with a handle, then you should set the userInfo field to 0 when you allocate the channel. The MyCreateSndChannel function defined in Listing 2-1 on page 2-20 automatically sets this field to 0.) After releasing the memory associated with the sound handle, the MyCheckSndChan procedure calls the MyDisposeSndChannel function (defined in Listing 2-3 on page 2-25) to release the memory occupied by both the sound channel and the sound channel record.
  2355. To ensure that the MyCheckSndChan procedure defined in Listing 2-20 does not attempt to dispose a channel before you have created one, you should initialize the gCallbackPerformed variable to FALSE. Also, you should initialize the gSndChan variable to NIL, so that other parts of your application can check to see if a sound is playing simply by checking this variable. For example, if your application must play a sound but another sound is currently playing, you might ensure that the application gives priority to the newer sound by stopping the old one. Listing 2-21 defines a procedure that stops the sound that is playing.
  2356. Listing 2-21    Stopping a sound that is playing asynchronously
  2357.  
  2358. PROCEDURE MyStopPlaying;
  2359. BEGIN
  2360.     IF gSndChan <> NIL THEN                                            {is sound really playing?}
  2361.         gCallbackPerformed := TRUE;                                        {set global flag}
  2362.     MyCheckSndChan;                                            {call routine to do disposing}
  2363. END;
  2364. Once you have defined a callback procedure, a routine that installs the callback procedure, a routine that checks the status of the callback procedure, and a routine that can stop sound play, you need only allocate a sound channel, call the SndPlay function, and install your callback procedure to start an asynchronous sound play. Listing 2-22 defines a procedure that starts an asynchronous play.
  2365. Listing 2-22    Starting an asynchronous sound play
  2366.  
  2367. PROCEDURE MyStartPlaying (mySndID: Integer);
  2368. CONST
  2369.     kAsync = TRUE;                                    {play is asynchronous}
  2370. VAR
  2371.     mySndHandle:                    Handle;                {handle to an 'snd ' resource}
  2372.     myErr:                    OSErr;
  2373. BEGIN
  2374.     IF gSndChan <> NIL THEN                                                    {check if channel is active}
  2375.         MyStopPlaying;
  2376.     gSndChan := MyCreateSndChannel(0, 0, @MyCallbackProc, stdQLength);
  2377.     mySndHandle := GetResource('snd ', mySndID);
  2378.     IF (mySndHandle <> NIL) AND (gSndChan <> NIL) THEN
  2379.     BEGIN                                    {start sound playing}
  2380.         DetachResource(mySndHandle);                                                {detach resource from file}
  2381.                                                         {remember to release sound handle}
  2382.         gSndChan^.userInfo := LongInt(mySndHandle);
  2383.         HLock(mySndHandle);                                                {lock the resource data}
  2384.         myErr := SndPlay(gSndChan, mySndHandle, kAsync);
  2385.         IF myErr = noErr THEN
  2386.             myErr := MyInstallCallback(gSndChan);
  2387.         IF myErr <> noErr THEN
  2388.             DoError(myErr);
  2389.     END;
  2390. END;
  2391. The MyStartPlaying procedure uses the MyCreateSndChannel function defined in Listing 2-1 to create a sound channel, requesting that the function allocate a standard-sized sound channel command queue. By using such a queue, you can be sure that your application can play any sound resource that contains up to 127 sound commands. If you are sure that your application will play only sampled-sound resources created by the Sound Input Manager, you should request a queue of only two sound commands, thereby leaving enough room for just the bufferCmd command contained within the sound resource and the callBackCmd command that your application issues. 
  2392. Before playing the sound, the MyStartPlaying procedure defined in Listing 2-22 detaches the sound resource from its resource file after loading it. This is important if the resource file could close while the sound is still playing, or if your application might create another sound channel to play the same sound resource while the sound is still playing. 
  2393. Synchronizing Sound With Other Actions
  2394.  
  2395. If your application uses callback procedures to play sound asynchronously, you might wish to synchronize sound play with other activity, such as an onscreen animation.
  2396. Callback procedures allow your application to do that by using different constant values in the param1 field of the callback command. For example, you could define a constant kFirstSoundFinished to signal to your application that the first of a series of sounds has finished playing. Then, your callback procedure could set an appropriate global flag depending on whether the param1 field equals kFirstSoundFinished, kSoundComplete, or some other constant that your application defines. Finally, a procedure that you call once each time through your application’s event loop could check to see which of the various global flag variables are set and respond appropriately. Meanwhile, sound continues to play.
  2397. Managing an Asynchronous Play From Disk
  2398.  
  2399. The Sound Manager allows you to play a sound file asynchronously with the SndStartFilePlay function by defining a completion routine that sets a global flag to alert the application to dispose of the sound channel when the sound is done playing. Completion routines are thus similar to callback procedures, but they are easier to use in that you do not need to install them. The Sound Manager automatically executes them when a play from disk ends, whether it has ended because the application called the SndStopFilePlay function, because the application disposed of the sound channel in which the sound was playing, or because the sound has finished playing.
  2400. You define a completion routine like this:
  2401. PROCEDURE MySoundCompletionRoutine (chan: SndChannelPtr);
  2402. Note that unlike callback procedures, completion routines have only one parameter, a pointer to a sound channel. Thus, for the completion routine to set the application’s A5 world properly, you should pass the value of the application’s A5 in the userInfo field of the sound channel, like this:
  2403. gSndChan^.userInfo := SetCurrentA5;
  2404. Then your completion routine can look in the userInfo field of the sound channel to set A5 correctly before it can access any application global variables. Listing 2-23 defines a completion routine that sets A5 correctly.
  2405. Listing 2-23    Defining a completion routine
  2406.  
  2407. PROCEDURE MySoundCompletionRoutine (chan: SndChannelPtr);
  2408. VAR
  2409.     myA5:            LongInt;
  2410. BEGIN
  2411.     myA5 := SetA5(chan^.userInfo);                                                {set my A5}
  2412.     gCompletionPerformed := TRUE;                                                {set a global flag}
  2413.     myA5 := SetA5(myA5);                                                {restore the original A5}
  2414. END;
  2415. The completion routine defined in Listing 2-23 sets a global flag variable to indicate that the completion routine has been called. To start a sound file playing, you can use a routine analogous to that defined in Listing 2-22, but when allocating a sound channel, you need only allocate a queue of a single sound command. You can than use a procedure analogous to that defined in Listing 2-20 to check the flag once each time through the application’s event loop and dispose of the sound channel if the flag is set.
  2416. If you do use the SndStartFilePlay function to play sounds asynchronously, then you can pause, restart, and stop play simply by using the SndPauseFilePlay and SndStopFilePlay functions.
  2417. You use SndPauseFilePlay to temporarily suspend a sound from playing. If a sound is playing and you call SndPauseFilePlay, then the sound is paused. If the sound is paused and you call SndPauseFilePlay again, then the sound resumes playing. Hence, the SndPauseFilePlay routine acts like a pause button on a tape player, which toggles the tape between playing and pausing. (You can determine the current state of a play from disk by using the SndChannelStatus function. See “Obtaining Information About a Single Sound Channel” on page 2-37 for more details.) Finally, you can use SndStopFilePlay to stop the file from playing.
  2418. Playing Selections
  2419.  
  2420. The sixth parameter passed to the SndStartFilePlay function is a pointer to an audio selection record, which allows you to specify that only part of the sound be played. If that parameter has a value different from NIL, then SndStartFilePlay plays only a specified selection of the entire sound. You indicate which part of the entire sound to play by giving two offsets from the beginning of the sound, a time at which to start the selection and a time at which to end the selection. Currently, both time offsets must be specified in seconds.
  2421. Here is the structure of an audio selection record:
  2422. TYPE AudioSelection =
  2423. PACKED RECORD
  2424.     unitType:                LongInt;                {type of time unit}
  2425.     selStart:                Fixed;                {starting point of selection}
  2426.     selEnd:                Fixed;                {ending point of selection}
  2427. END;
  2428. To play a selection, you should specify in the selStart and selEnd fields the starting and ending point in seconds of the sound to play. Also, you must set the unitType field to the constant unitTypeSeconds.
  2429. If you wish to play an entire sound, you can simply pass NIL to the SndStartFilePlay function. Alternatively, you can set the unitType field to the constant unitTypeNoSelection, in which case the values in the selStart and selEnd fields are ignored. 
  2430. Managing Multiple Sound Channels
  2431.  
  2432. If you are writing an application that can play multiple channels of sound on Macintosh computers that support that feature, you can use the Sound Manager’s asynchronous playing abilities, but you might encounter some special obstacles. The technique for playing sounds asynchronously described in “Playing Sounds Asynchronously” on page 2-46 has a limitation if you are using multiple sound channels. Using that technique without modification, you would need to define each separate sound channel in a different global variable, and you would need to use several global flags in your callback procedure to signal which sound channels have finished processing sound commands.
  2433. Although it is easy to modify the code in “Playing Sounds Asynchronously” to use several flags, this solution might not be satisfactory for an application in which the number of sound channels open can vary. For example, suppose that you are writing entertainment software with dozens of sound effects that correspond to actions on the screen and you wish to use the Sound Manager asynchronously so that several sound effects can be played at once. It would be cumbersome to associate a separate global sound channel variable with each sound and create a flag variable for each of these sound channels. Also, you might wish to play the same sound simultaneously in two separate channels. It would be better to write code that manages a global list of sound channels and then provides a simple routine that allows you to add a channel to the list. This section shows how you might implement such a list of sound channels. Listing 2-24 defines a data structure that you could use to track multiple sound channels.
  2434. Listing 2-24    Defining a data structure to track many sound channels
  2435.  
  2436. CONST
  2437.     kMaxNumSndChans = 20;                                            {max number of sound channels}
  2438. TYPE
  2439.     SCInfo = 
  2440.     RECORD
  2441.         sndChan:                     SndChannelPtr;                    {NIL or pointer to channel}
  2442.         mustDispose:                     Boolean;                    {flag to dispose channel}
  2443.         itsData:                     Handle;                    {data to dispose with channel}
  2444.     END;
  2445.     SCList = ARRAY[1..kMaxNumSndChans] OF SCInfo;
  2446. VAR
  2447.     gSndChans:                        SCList;
  2448. The SCInfo data structure defined in Listing 2-24 allows you to keep track of which channels in the collection are being used and which were being used but currently need disposal; it also allows you to associate data with a sound channel so that you can dispose of the data when you dispose of the sound channel. Note that the value of the kMaxNumSndChans constant might vary from application to application. Having defined the data structure, you must initialize it (so that the sndChan and itsData fields are NIL and the mustDispose field is FALSE). You must also write a procedure that finds an available channel. You might declare such a procedure like this:
  2449. PROCEDURE DoTrackChan (chanToTrack: SndChannelPtr; associatedData: Handle);
  2450. Using such a procedure, you could simply create sound channels by using local variables and then add them to the tracking list so that your application disposes of them when they finish executing. The exact implementation of such a procedure would depend on the needs of your application. For example, if there are no channels available in the global list of sound channels, your application might report an error, stop sound on all active channels, or stop sound on the channel that has been playing the longest. If you want your application to be compatible with computers that do not support multichannel sound, this procedure could check whether multichannel sound is supported, and if not, would stop any sound playing on other channels. This is particularly useful if your application plays sound effects in response to actions on the screen; overlapping sound effects sound best, but if this is unattainable, the newest sound should have the highest priority.
  2451. One advantage of maintaining a list of sound channels is that you can use it in conjunction with both callback procedures and completion routines. Listing 2-25 defines a procedure that either your callback procedure or completion routine could call after setting the application’s A5 world correctly.
  2452. Listing 2-25    Marking a channel for disposal
  2453.  
  2454. PROCEDURE MySetTrackChanDispose (mySndChannel: SndChannelPtr);
  2455. VAR
  2456.     index:                Integer;                    {channel index}
  2457.     found:                Boolean;                    {flag variable}
  2458. BEGIN
  2459.     index := 1;                                    {start at first spot}
  2460.     found := FALSE;                                    {initialize flag variable}
  2461.     WHILE (index <= kMaxNumSndChans) AND (NOT found) DO
  2462.         IF gSndChans[index].sndChan = mySndChannel THEN
  2463.             found := TRUE                            {proper channel found}
  2464.         ELSE
  2465.             index := index + 1;                            {move to next spot}
  2466.     IF found THEN
  2467.         gSndChans[index].mustDispose := TRUE;
  2468. END;
  2469. The final thing you need to do is to define a procedure that your application calls once each time through its main event loop. This procedure must dispose of sound channels that are marked for disposal. Listing 2-26 defines such a routine.
  2470. Listing 2-26    Disposing of channels that have been marked for disposal
  2471.  
  2472. PROCEDURE MyCleanUpTrackedChans;
  2473. CONST
  2474.     kQuietNow = TRUE;                                                            {need to quiet channel?}
  2475. VAR
  2476.     index:                Integer;
  2477.     myErr:                OSErr;
  2478. BEGIN
  2479.     FOR index := 1 TO kMaxNumSndChans DO                                                            {go through all channels}
  2480.     WITH gSndChans[index] DO
  2481.         IF mustDispose THEN                                                        {check global flag}
  2482.         BEGIN                                                        {channel needs disposal}
  2483.             IF gSndChans[index].itsData <> NIL THEN
  2484.             BEGIN                                                    {release other data}
  2485.                 HUnlock(gSndChans[index].itsData);
  2486.                 HPurge(gSndChans[index].itsData);
  2487.             END;
  2488.                                                                 {free channel-related memory}
  2489.             myErr := MyDisposeSndChannel(sndChan, kQuietNow);
  2490.             sndChan := NIL;                                                    {set pointer to NIL}
  2491.             mustDispose := FALSE;                                                    {reset global flag}
  2492.             IF myErr <> noErr THEN 
  2493.                 DoError(myErr);
  2494.         END;
  2495. END;
  2496. The MyCleanUpTrackedChans procedure defined in Listing 2-26 works just like the MyCheckSndChan procedure defined in Listing 2-20, but instead of checking a single global flag, it checks the flag associated with each allocated sound channel. Now that you have defined such a procedure, you can easily write a routine to stop sound in all active channels (for example, if your application receives a suspend event). Simply set the mustDispose flag on all sound channels that are allocated (that is for all channels that are not NIL) and then call MyCleanUpTrackedChans. Note, however, that when the MyCleanUpTrackedChans procedure disposes of a sound channel processing a play from disk, the completion routine will be called and will thus set the mustDispose flag to TRUE. Thus, the mustDispose flag must be reset to FALSE after the sound channel has been disposed. Otherwise, the MyCleanUpTrackedChans procedure would try to dispose of the same sound channel again when the application called it from its main event loop.
  2497. Parsing Sound Resources and Sound Files
  2498.  
  2499. This section explains how you can parse sound resources and sound files to find the component of a sound resource or sound file that contains information about the sound. For sound resources, this information is stored in the sound header. In addition to obtaining information about a sound from a sound header, you might need a pointer to a sound header to use any of several low-level sound commands. For sound files, information is stored in the Form and Common Chunks. This section shows how you can find those chunks and extract information from them.
  2500. Note
  2501. The techniques shown in this section assume that you are familiar with the format of sound resources and sound files. See “Sound Storage Formats” beginning on page 2-73 for complete information on sound storage formats.u
  2502. Obtaining a Pointer to a Sound Header
  2503.  
  2504. This section shows how you can obtain a pointer to a sound header stored in a sound resource. You can use this pointer to obtain information about the sound. You also need a pointer to a sound header to install a sampled sound as a voice in a channel (as described in “Installing Voices Into Channels” on page 2-43) and to play sounds using low-level sound commands (as described below and in the next section). You can use a technique similar to the one described in this section if you wish to obtain a pointer to wave-table data that is stored in a sound resource.
  2505. Sound Manager versions 3.0 and later include the GetSoundHeaderOffset function that you can use to locate a sound header embedded in a sound resource. Listing 2-27 shows how to call the GetSoundHeaderOffset function and then pass the returned offset to the bufferCmd sound command, to play a sampled sound using low-level Sound Manager routines.
  2506. Listing 2-27    Playing a sound resource
  2507.  
  2508. FUNCTION MyPlaySampledSound (chan: SndChannelPtr; sndHandle: Handle): OSErr;
  2509. VAR
  2510.     myOffset:                    LongInt;
  2511.     mySndCmd:                    SndCommand;                            {a sound command}
  2512.     myErr:                    OSErr;
  2513. BEGIN
  2514.     myErr := GetSoundHeaderOffset(sndHandle, myOffset);
  2515.     IF myErr = noErr THEN
  2516.     BEGIN
  2517.         HLock(sndHandle);
  2518.         mySndCmd.cmd := bufferCmd;                                                        {command is bufferCmd}
  2519.         mySndCmd.param1 := 0;                                                        {unused with bufferCmd}
  2520.         mySndCmd.param2 := LongInt(ORD4(sndHandle^) + myOffset);
  2521.         myErr := SndDoImmediate(chan, mySndCmd);
  2522.     END;
  2523.     MyPlaySampledSound := myErr;
  2524. END;
  2525. If the GetSoundHeaderOffset function is not available but you still need to obtain a pointer to a sound header, you can use the function MyGetSoundHeaderOffset defined in Listing 2-28. The function defined there traverses a sound resource until it reaches the sound data. It returns, in the offset parameter, the offset in bytes from the beginning of a sound resource to the sound header.
  2526. IMPORTANT
  2527. IMPORTANT
  2528. The GetSoundHeaderOffset function is available in Sound Manager versions 3.0 and later. As a result, you’ll need to use the techniques illustrated in Listing 2-28 only if you want your application to find a sound header when earlier versions of the Sound Manager are available.s
  2529. Listing 2-28    Obtaining the offset in bytes to a sound header
  2530.  
  2531. FUNCTION MyGetSoundHeaderOffset (sndHdl: Handle; VAR offset: LongInt): OSErr;
  2532. TYPE
  2533.     Snd1Header =                                                     {format 1 'snd ' resource header}
  2534.     RECORD
  2535.         format:                 Integer;                                {format of resource}
  2536.         numSynths:                Integer;                                {number of data types}
  2537.                                                         {synths, init option follow}
  2538.     END;
  2539.     Snd1HdrPtr = ^Snd1Header;
  2540.     Snd2Header =                                                     {format 2 'snd ' resource header}
  2541.     RECORD
  2542.         format:                 Integer;                                {format of resource}
  2543.         refCount:                Integer;                                {for application use}
  2544.     END;
  2545.     Snd2HdrPtr = ^Snd2Header;
  2546.     IntPtr = ^Integer;                                                    {for type coercion}
  2547.     SndCmdPtr = ^SndCommand;                                                    {for type coercion}
  2548. VAR
  2549.     myPtr:                    Ptr;                                {to navigate resource}
  2550.     myOffset:                    LongInt;                                {offset into resource}
  2551.     numSynths:                    Integer;                                {info about resource}
  2552.     numCmds:                    Integer;                                {info about resource}
  2553.     isDone:                    Boolean;                                {are we done yet?}
  2554.     myErr:                    OSErr;
  2555. BEGIN
  2556.     {Initialize variables.}
  2557.     myOffset := 0;                                                    {return 0 if no sound header found}
  2558.     myPtr := Ptr(sndHdl^);                                                    {point to start of resource data}
  2559.     isDone := FALSE;                                                    {haven't yet found sound header}
  2560.     myErr := noErr;
  2561.  
  2562.     {Skip everything before sound commands.}
  2563.     CASE Snd1HdrPtr(myPtr)^.format OF
  2564.         firstSoundFormat:                                                {format 1 'snd ' resource}
  2565.             BEGIN                                            {skip header start, synth ID, etc.}
  2566.                 numSynths := Snd1HdrPtr(myPtr)^.numSynths;
  2567.                 myPtr := Ptr(ORD4(myPtr) + SizeOf(Snd1Header));
  2568.                 myPtr := Ptr(ORD4(myPtr) + 
  2569.                                 numSynths * (SizeOf(Integer) + SizeOf(LongInt)));
  2570.             END;
  2571.         secondSoundFormat:                                                {format 2 'snd ' resource}
  2572.             myPtr := Ptr(ORD4(myPtr) + SizeOf(Snd2Header));
  2573.         OTHERWISE                                                {unrecognized resource format}
  2574.             BEGIN
  2575.                 myErr := badFormat;
  2576.                 isDone := TRUE;
  2577.             END;
  2578.         END;
  2579.  
  2580.     {Find number of commands and move to start of first command.}
  2581.     numCmds := IntPtr(myPtr)^;
  2582.     myPtr := Ptr(ORD4(myPtr) + SizeOf(Integer));
  2583.  
  2584.     {Search for bufferCmd or soundCmd to obtain sound header.}
  2585.     WHILE (numCmds >= 1) AND (NOT isDone) DO
  2586.     BEGIN
  2587.         IF (IntPtr(myPtr)^ = bufferCmd + dataOffsetFlag) OR
  2588.                 (IntPtr(myPtr)^ = soundCmd + dataOffsetFlag) THEN
  2589.         BEGIN                                                {bufferCmd or soundCmd found}
  2590.                                                         {copy offset from sound command}
  2591.             myOffset := SndCmdPtr(myPtr)^.param2;
  2592.             isDone := TRUE;                                            {get out of loop}
  2593.         END
  2594.         ELSE
  2595.         BEGIN                                                {soundCmd or bufferCmd not found}
  2596.                                                         {move to next command}
  2597.             myPtr := Ptr(ORD4(myPtr) + SizeOf(SndCommand));
  2598.             numCmds := numCmds - 1;
  2599.         END;
  2600.     END; {WHILE}
  2601.  
  2602.     offset := myOffset;                                                    {return offset}
  2603.     MyGetSoundHeaderOffset := myErr;                                                    {return result code}
  2604. END;
  2605. The MyGetSoundHeaderOffset function defined in Listing 2-28 begins by initializing several variables, including a pointer that it sets to point to the beginning of the data contained in the sound resource. Then, after determining whether the sound resource is format 1 or format 2, the function skips data contained in the format 1 'snd ' resource header or in the format 2 'snd ' resource header, as appropriate.
  2606. Note
  2607. Do not confuse the format 1 or format 2 'snd ' header with the sound header the MyGetSoundHeaderOffset function defined in Listing 2-28 is designed to find. A sound header contains information about the sampled-sound data stored in a sound resource; a sound resource header contains information about the format of the sound resource.u
  2608. After skipping information in the sound resource header, MyGetSoundHeaderOffset simply looks through all sound commands in the resource for a bufferCmd or soundCmd command, either of which must contain the offset from the beginning of the resource to the sound header in its param2 field. If the given sound resource contains no sound header (and thus no sampled-sound data), the MyGetSoundHeaderOffset function returns an error and sets the offset variable parameter to 0.
  2609. After using the MyGetSoundHeaderOffset function to obtain an offset to the sound header, you can easily obtain a pointer to a sound header. Note, however, that because a handle to a sound resource is contained in a relocatable block, you must lock the relocatable block before you obtain a pointer to a sound header, and you must not unlock it until you are through using the pointer. Listing 2-29 demonstrates how you can convert an offset to a sound header into a pointer to a sound header after locking a relocatable block.
  2610. Listing 2-29    Converting an offset to a sound header into a pointer to a sound header
  2611.  
  2612. FUNCTION MyGetSoundHeader (sndHandle: Handle): SoundHeaderPtr;
  2613. VAR
  2614.     myOffset:                 LongInt;                        {offset to sound header}
  2615.     myErr:                OSErr;
  2616. BEGIN
  2617.     HLockHi(sndHandle);                                        {lock data in high memory}
  2618.                                             {compute offset to sound header}
  2619.     myErr := MyGetSoundHeaderOffset(sndHandle, myOffset);
  2620.     IF myErr <> noErr THEN
  2621.         MyGetSoundHeader := NIL                                    {no sound header in resource}
  2622.     ELSE
  2623.                                             {compute address of sound header}
  2624.         MyGetSoundHeader := SoundHeaderPtr(ORD4(sndHandle^) + myOffset);
  2625. END;
  2626. The MyGetSoundHeader function defined in Listing 2-29 locks the sound handle you pass it in high memory and then attempts to find an offset to the sound header in the sound handle. If the MyGetSoundHeaderOffset function defined in Listing 2-28 returns an offset of 0, then MyGetSoundHeader returns a NIL pointer to a sound header; otherwise, it returns a pointer that remains valid as long as you do not unlock the sound handle.
  2627. The MyGetSoundHeader function returns a pointer to a sampled sound header even if the sound header is actually an extended sound header or a compressed sound header. Thus, before accessing any other fields of the sound header, you should test the encode field of the sound header to determine what type of sound header it is. Then, if the sound header is, for example, an extended sound header, cast the sampled sound header to an extended sound header. Then you can access any of the fields of the extended sound header. For an example of this technique, see Listing 2-16 on page 2-44.
  2628. Playing Sounds Using Low-Level Routines
  2629.  
  2630. Once you obtain a pointer to a sampled sound header, you can use the bufferCmd sound command to play a sound without using the high-level Sound Manager routines. Many sampled-sound resources include bufferCmd commands, so the high-level Sound Manager routines often issue the bufferCmd command indirectly. Thus, you might in some cases be able to make your application slightly more efficient by issuing the bufferCmd command directly. Also, you might issue a bufferCmd command directly if you want the Sound Manager to ignore other parts of a sound resource.
  2631. Finally, you might issue bufferCmd commands directly if you want your application to be able to play a large sound resource without loading the entire resource at once. By issuing several successive bufferCmd commands, you can play a large sound resource using a small buffer. In this case, each buffer must contain a sampled sound header. In most cases, the sound will play smoothly, without audible gaps. It’s generally easier, however, to play large sampled sounds from disk by using the play-from-disk routines or the SndPlayDoubleBuffer function. See “Managing Double Buffers” on page 2-147 for complete details.
  2632. Note
  2633. Using the bufferCmd command to play several consecutive compressed samples on the Macintosh Plus, the Macintosh SE, or the Macintosh Classic is not guaranteed to work without an audible pause or click.u 
  2634. The pointer in the param2 field of a bufferCmd command is the location of a sampled sound header. A bufferCmd command is queued in the channel until the preceding commands have been processed. If the bufferCmd command is contained within an 'snd ' resource, the high bit of the command must be set. If the sound was loaded in from an 'snd ' resource, your application is expected to unlock this resource and allow it to be purged after using it. Listing 2-30 shows how your application can play a sampled sound stored in a resource using the bufferCmd command.
  2635. Listing 2-30    Playing a sound using the bufferCmd command
  2636.  
  2637. FUNCTION MyLowLevelSampledSndPlay (chan: SndChannelPtr; sndHandle: Handle): 
  2638.                                                 OSErr;
  2639. CONST
  2640.     kWaitIfFull = TRUE;                                                {wait for room in queue?}
  2641. VAR
  2642.     mySndHeader:                    SoundHeaderPtr;
  2643.     mySndCmd:                    SndCommand;                            {a sound command}
  2644. BEGIN
  2645.     mySndHeader := MyGetSoundHeader(sndHandle);
  2646.     WITH mySndCmd DO
  2647.     BEGIN
  2648.         cmd := bufferCmd;                                            {command is bufferCmd}
  2649.         param1 := 0;                                            {unused with bufferCmd}
  2650.         param2 := LongInt(mySndHeader);                                            {pointer to sound header}
  2651.     END;
  2652.     IF mySndHeader <> NIL THEN
  2653.         MyLowLevelSampledSndPlay := 
  2654.                                         SndDoCommand(chan, mySndCmd, NOT kWaitIfFull)
  2655.     ELSE
  2656.         MyLowLevelSampledSndPlay := badFormat;
  2657. END;
  2658. For the MyLowLevelSampledSndPlay function defined in Listing 2-30 to play a sound, the channel passed to it must already be configured to play sampled-sound data. Otherwise, the function returns a badChannel result code. Also, because the bufferCmd command works asynchronously, you might want to associate a callback procedure with the sound channel when you create the channel. For more information on playing sounds asynchronously, see “Playing Sounds Asynchronously” on page 2-46.
  2659. You can use the bufferCmd command to handle compressed sound samples in addition to sounds that are not compressed. To expand and play back a buffer of compressed samples, you pass the Sound Manager a bufferCmd command where param2 points to a compressed sound header.
  2660. To play sampled sounds that are not compressed, pass bufferCmd a standard or extended sound header. The extended sound header can be used for stereo sampled sounds. The standard sampled sound header is used for all other noncompressed sampled sounds.
  2661. Finding a Chunk in a Sound File
  2662.  
  2663. Sound files are not as tightly structured as sound resources. As explained in “Sound Files” on page 2-81, the chunks in a sound file can appear in any order, except that the Form Chunk is always first. Most information about a sampled sound stored in a sound file is contained in the Common Chunk. Thus, to be able to access this information, you must be able to find a particular kind of chunk in a sound file. Listing 2-31 defines a procedure that you can use to find the location of the first chunk of a specified type beginning at the chunk you specify.
  2664. IMPORTANT
  2665. The techniques illustrated in this section are provided primarily to help you understand the structure of sound files. Most sound-producing applications don’t need to parse sound files.s
  2666. Listing 2-31    Finding a chunk in a sound file
  2667.  
  2668. FUNCTION MyFindChunk (myFile: Integer;                                                            {file reference number}
  2669.                             myChunkSought: ID;                                {ID of chunk sought}
  2670.                             startPos: LongInt;                                {file position to start at}
  2671.                             VAR chunkFPos: LongInt)                                {file position of found chunk}
  2672.                             : OSErr;
  2673. VAR
  2674.     myLength:                        LongInt;                                {number of bytes to read}
  2675.     myChunkHeader:                        ChunkHeader;                                {characteristics of chunk}
  2676.     found:                        Boolean;                                {flag variable}
  2677.     myErr:                        OSErr;                                {error from File Manager calls}
  2678. BEGIN
  2679.     found := FALSE;                                                        {initialize flag variable}
  2680.                                                             {set file mark at start}
  2681.     myErr := SetFPos(myFile, fsFromStart, startPos);
  2682.  
  2683.     {Search file's chunks for desired chunk ID.}
  2684.     WHILE (NOT found) AND (myErr = noErr) DO
  2685.     BEGIN                                                        {check current chunk}
  2686.         myLength := SizeOf(myChunkHeader);
  2687.         {Load chunk header.}
  2688.         myErr := FSRead(myFile, myLength, @myChunkHeader);
  2689.         IF myErr = noErr THEN                                                    {chunk header loaded okay}
  2690.             IF myChunkHeader.ckID = myChunkSought THEN
  2691.             BEGIN
  2692.                 found := TRUE;                                            {chunk has been found}
  2693.                                                             {find position in file}
  2694.                 myErr := GetFPos(myFile, chunkFPos);
  2695.                                                             {compute chunk's start position}
  2696.                 chunkFPos := chunkFPos - SizeOf(myChunkHeader);
  2697.             END
  2698.             ELSE
  2699.             BEGIN                                                {move to next chunk}
  2700.                 IF myChunkHeader.ckID = ID(FormID) THEN
  2701.                     {Adjust Form Chunk's size to size of formType field.}
  2702.                     myChunkHeader.ckSize := SizeOf(ID);
  2703.                 IF myChunkHeader.ckSize MOD 2 = 1 THEN
  2704.                     {Compensate for pad byte.}
  2705.                     myChunkHeader.ckSize := myChunkHeader.ckSize + 1;
  2706.                 myErr := SetFPos(myFile, fsFromMark, myChunkHeader.ckSize);
  2707.             END;
  2708.     END; {WHILE}
  2709.     MyFindChunk := myErr;
  2710. END;
  2711. The MyFindChunk function defined in Listing 2-31 accepts four parameters. The myFile parameter is the file reference number of an open sound file. (For information on file reference numbers, see Inside Macintosh: Files.) In the myChunkSought parameter, you pass the ID of the type of chunk you wish to find. For example, you might pass ID(FormID) to find the Form Chunk. The third parameter, startPos, is the file position at which MyFindChunk should start searching for a chunk. This file position must be the beginning of a chunk. To start at the beginning of a file, specify 0. Finally, if the MyFindChunk function is successful, it returns in the chunkFPos parameter the file position of the first chunk of the specified type that it found. If the function is unsuccessful, it returns the appropriate File Manager result code (such as an end-of-file error) and the chunkFPos parameter is undefined.
  2712. The MyFindChunk function works by looking at each chunk of the sound file, beginning at the file position startPos and checking to see if the chunk is of the type sought. If a chunk matches, the MyFindChunk function returns the file position of the start of the chunk; otherwise, the function moves onto the next chunk. For each chunk, the MyFindChunk function reads in the chunk header, checks for a match, and then moves to the next chunk.
  2713. The MyFindChunk function moves from one chunk to the next by identifying the size of the current chunk, not including the chunk header, from the ckSize field of the chunk header. Whenever you parse sound files, you should always use the ckSize field of the chunk header to determine the size of a chunk if the size of the chunk could vary in size. The MyFindChunk function adjusts the value in the ckSize field before advancing to the next chunk in two cases. First, the ckSize field for the Form Chunk reflects the size of the entire sound file, so this function changes it to the size of the formType field so that the function does not skip the file’s local chunks. Second, if the ckSize field is odd, 1 byte is added because the number of bytes in a chunk is always even.
  2714. After using the MyFindChunk function defined in Listing 2-31, you might still need to read the data contained in a chunk into memory. For example, you might read in the Form and Common Chunks to obtain information about a sound file. Listing 2-32 uses the MyFindChunk function to find a chunk in a sound file, allocates an appropriately sized block of memory for that chunk, and reads the chunk into that block.
  2715. Listing 2-32    Loading a chunk from a sound file
  2716.  
  2717. FUNCTION MyGetChunkData (myFile: Integer;                                                                {file reference number}
  2718.                                     myChunkSought: ID;                            {ID of chunk sought}
  2719.                                     startPos: LongInt):                            {file position to start at}
  2720.                                     Ptr;                            {pointer to data or NIL}
  2721. VAR
  2722.     myFPos:                        LongInt;                                    {position in file}
  2723.     myLength:                        LongInt;                                    {number of bytes to read}
  2724.     myChunkHeader:                        ChunkHeader;                                    {characteristics of a chunk}
  2725.     myChunkData:                        Ptr;                                    {pointer to chunk data}
  2726.     myErr:                        OSErr;
  2727. BEGIN
  2728.     myChunkData := NIL;                                                            {initialize variable}
  2729.     myErr := MyFindChunk(myFile, myChunkSought, startPos, myFPos);
  2730.     IF myErr = noErr THEN
  2731.                                                                 {move to start of chunk}
  2732.         myErr := SetFPos(myFile, fsFromStart, myFPos);
  2733.     IF myErr = noErr THEN
  2734.     BEGIN                                                {determine how much data to copy}
  2735.         myLength := SizeOf(ChunkHeader);
  2736.         myErr := FSRead(myFile, myLength, @myChunkHeader);
  2737.         IF myChunkHeader.ckID = ID(FormID) THEN
  2738.             myChunkHeader.ckSize := SizeOf(ID);                                                    {don't return local chunks}
  2739.         myLength := myChunkHeader.ckSize + SizeOf(ChunkHeader);
  2740.         IF myErr = noErr THEN
  2741.                                                                 {return to chunk's start}
  2742.             myErr := SetFPos(myFile, fsFromStart, myFPos);
  2743.     END;
  2744.     IF myErr = noErr THEN
  2745.     BEGIN                                                    {read chunk data into RAM}
  2746.         myChunkData := NewPtr(myLength);
  2747.         IF myChunkData <> NIL THEN
  2748.             myErr := FSRead(myFile, myLength, myChunkData);
  2749.     END;
  2750.     IF myErr <> noErr THEN
  2751.         IF myChunkData <> NIL THEN
  2752.             DisposePtr(myChunkData);
  2753.     MyGetChunkData := myChunkData;
  2754. END;
  2755. The MyGetChunkData function defined in Listing 2-32 attempts to find a chunk in a file. If it finds the chunk, it reads the chunk header to determine the chunk’s size, and if the chunk is the Form Chunk, adjusts the chunk size so that the sound file’s local chunks are not included in the chunk size. Then the function attempts to allocate memory for the chunk and read the chunk into the memory. If a problem occurs at any time, the function simply returns NIL.
  2756. Note
  2757. The format of a sound file might not be the same as its operating-system type. In particular, a file might have an operating-system type 'AIFC' but be formatted as an AIFF file because the sampled-sound data contained in the file is noncompressed.u 
  2758. Compressing and Expanding Sounds
  2759.  
  2760. Some of the capabilities provided by MACE are transparently available to your application. For example, if you pass the SndPlay function a handle to an 'snd ' resource that contains a compressed sampled sound, the Sound Manager automatically expands the sound data for playback in real time. Your application does not need to know whether the 'snd ' resource contains compressed or noncompressed samples when it calls SndPlay. This is because sufficient information is in the resource itself to allow the Sound Manager to determine whether it should expand the data samples.
  2761. However, aside from expansion playback, all of the MACE capabilities need to be specifically requested by your application. For example, you can use the procedure Comp3to1 or Comp6to1 if you want to compress a sampled sound (for example, to create an 'snd ' resource containing compressed audio data). You can use the procedures Exp1to3 and Exp1to6 to expand compressed audio data.
  2762. All of these procedures require you to specify both an input and an output buffer, from and to which the sampled-sound data to be converted is read and written. Your application must allocate the appropriate amount of storage for each buffer. For example, if you want to expand a buffer of compressed monophonic sampled-sound data by using Exp1to6, the output buffer must be at least six times the size of the input buffer.
  2763. The MACE compression and expansion routines can work on only one channel of sound. The numChannels parameter of all four procedures allows you to specify how many channels are in the original sample, and the whichChannel parameter allows you to specify which channel you wish to compress or expand. Because the MACE routines can compress or expand only one channel of sound, you must make adjustments when allocating an output buffer for stereo sound. For example, if you are compressing two-channel sound using the Comp3to1 procedure, your output buffer need only be one-sixth the size of your input buffer.
  2764. Often when compressing polyphonic sound, being able to compress only one channel is not a problem, because you lose sound quality during compression anyway. However, you might at times wish to maintain more than one channel of a multichannel sound even after compression and expansion. For example, two channels of a stereo sound might be quite different and might both be necessary to achieve a full sound after expansion. In these cases, you can compress each channel of a multichannel sound individually and then manually interleave the samples on a packet basis. When you expand polyphonic compressed sound data, you must interleave the channels of sound on a sample frame basis. 
  2765. The MACE routines work only with sampled-sound data in offset binary format. If you are compressing data in a sound file, you must convert that data from linear, two’s complement format to binary offset format before compression.
  2766. When calling the MACE routines, you can also specify addresses of two small buffers (128 bytes each) that the Sound Manager uses to maintain state information about the compression or expansion process. When you first call a MACE routine, the state buffers should be filled with zeros to initialize the state information. When you subsequently call another MACE routine, you can use the same state buffers. You can pass NIL for both buffers if you do not want to save state information across calls to the MACE routines. Listing 2-33 illustrates the use of the Comp3to1 procedure when using state buffers.
  2767. Listing 2-33    Compressing audio data
  2768.  
  2769. PROCEDURE MyCompressBy3 (inBuf: Ptr; outBuf: Ptr; numSamp: LongInt);
  2770. CONST 
  2771.     kStateBufferSize = 128;
  2772. VAR
  2773.     myInState:                        Ptr;            {input state buffer}
  2774.     myOutState:                        Ptr;            {output state buffer}
  2775. BEGIN
  2776.     myInState := NewPtrClear(kStateBufferSize);
  2777.     myOutState := NewPtrClear(kStateBufferSize);
  2778.     IF (myInState <> NIL) AND (myOutState <> NIL) THEN
  2779.         Comp3to1(inBuf, outBuf, numSamp, myInState, myOutState, 1, 1);
  2780. END;
  2781. Because the last two parameters (numChannels and whichChannel) are both set to 1, MyCompressBy3 compresses monophonic audio data.
  2782. In practice, compressing a sound resource or sound file is considerably more complex than calling the MyCompressBy3 procedure defined in Listing 2-33. To compress a sound resource containing monophonic sampled-sound data, you would need to
  2783. n    load the data into a handle and lock the handle
  2784. n    ensure that the data in the handle is not already compressed by examining the sound header
  2785. n    find a pointer to the sampled-sound data by examining the samplePtr field of the sound header
  2786. n    allocate an output buffer of the appropriate size, taking into account that only one channel of the original data can be compressed
  2787. n    compress the sampled-sound data by calling the Comp3To1 procedure
  2788. n    determine the size that the header information (including, for example, sound commands and the sampled sound header excluding the sampled-sound data itself) will take in the resource by using the Sound Input Manager’s SetupSndHeader function to create a sound resource header and sampled sound header with the same sample rate, base frequency, and other characteristics as the original sampled-sound data
  2789. n    resize the handle so that it is large enough to contain both the non–sampled-sound data information and the compressed sound data
  2790. n    fill this handle by first calling SetupSndHeader once again and by then copying the compressed sound data to the end of the header information
  2791. n    update the resource file
  2792. Techniques for compressing sound files and for expanding both sound resources and sound files are analogous to that sketched here. Remember that after compressing or expanding each channel of polyphonic sampled-sound data, you must interleave frames of sound data, on a packet basis after compression or on a sample basis after expansion.
  2793. Using Double Buffers
  2794.  
  2795. The play-from-disk routines make extensive use of the SndPlayDoubleBuffer function. You can use this function in your application directly if you wish to bypass the normal play-from-disk routines. You might want to do this to maximize the efficiency of your application while maintaining compatibility with the Sound Manager. Or, you might define your own double-buffering routines so that your application can convert 16-bit sound data on disk to 8-bit data that all versions of the Sound Manager can play. By using SndPlayDoubleBuffer instead of the normal play-from-disk routines, you can specify your own doubleback procedure (that is, the algorithm used to switch back and forth between buffers) and customize several other buffering parameters.
  2796. IMPORTANT
  2797. SndPlayDoubleBuffer is a very low-level routine and is not intended for general use. In most cases, you should use the high-level Sound Manager routines (such as SndPlay or SndStartFilePlay) or standard sound commands (such as bufferCmd) to play sounds. You should use SndPlayDoubleBuffer only if you require very fine control over double buffering. Remember also that the SndPlayDoubleBuffer function is not always available. You’ll need to ensure that it’s available in the current operating environment before calling it. See “Testing for Multichannel Sound and Play-From-Disk Capabilities” beginning on page 2-35 for details.s 
  2798. You call SndPlayDoubleBuffer by passing it a pointer to a sound channel (into which the double-buffered data is to be written) and a pointer to a sound double buffer header record. Here’s an example:
  2799. myErr := SndPlayDoubleBuffer(mySndChan, @myDoubleHeader);
  2800. A sound double buffer header record has the following structure:
  2801. TYPE SndDoubleBufferHeader =
  2802. PACKED RECORD
  2803.     dbhNumChannels:                        Integer;                {number of sound channels}
  2804.     dbhSampleSize:                        Integer;                {sample size, if noncompressed}
  2805.     dbhCompressionID:                        Integer;                {ID of compression algorithm}
  2806.     dbhPacketSize:                        Integer;                {number of bits per packet}
  2807.     dbhSampleRate:                        Fixed;                {sample rate}
  2808.     dbhBufferPtr:                        ARRAY[0..1] OF SndDoubleBufferPtr;
  2809.                                             {pointers to SndDoubleBuffer}
  2810.     dbhDoubleBack:                        ProcPtr;                {pointer to doubleback procedure}
  2811. END;
  2812. The values for the dbhCompressionID, dbhNumChannels, and dbhPacketSize fields are the same as those for the compressionID, numChannels, and packetSize fields of the compressed sound header, respectively.
  2813. The dbhBufferPtr array contains pointers to two records of type SndDoubleBuffer. These are the two buffers between which the Sound Manager switches until all the sound data has been sent into the sound channel. When the call to SndPlayDoubleBuffer is made, the two buffers should both already contain a nonzero number of frames of data.
  2814. IMPORTANT
  2815. The Sound Manager defines the data type SndDoubleBufferHeader2 that is identical to the SndDoubleBufferHeader data type except that it contains the dbhFormat field (of type OSType) that defines a custom codec to be used to decompress the sound data. The dbhFormat field is used only if the dbhCompressionID field contains the value fixedCompression. See “Sound Double Buffer Header Records” beginning on page 2-111 for details.s
  2816. Here is the structure of a sound double buffer:
  2817. TYPE SndDoubleBuffer =
  2818. PACKED RECORD
  2819.     dbNumFrames:                    LongInt;                    {number of frames in buffer}
  2820.     dbFlags:                    LongInt;                    {buffer status flags}
  2821.     dbUserInfo:                    ARRAY[0..1] OF LongInt;
  2822.                                             {for application's use}
  2823.     dbSoundData:                    PACKED ARRAY[0..0] OF Byte;
  2824.                                             {array of data}
  2825. END;
  2826. The buffer status flags field for each of the two buffers might contain either of these values:
  2827. CONST
  2828.     dbBufferReady                        = $00000001;
  2829.     dbLastBuffer                        = $00000004;
  2830. All other bits in the dbFlags field are reserved by Apple; your application should not modify them.
  2831. The following two sections illustrate how to fill out these data structures, create your two buffers, and define a doubleback procedure to refill the buffers when they become empty.
  2832. Setting Up Double Buffers
  2833.  
  2834. Before you can call SndPlayDoubleBuffer, you need to allocate two buffers (of type SndDoubleBuffer), fill them both with data, set the flags for the two buffers to dbBufferReady, and then fill out a record of type SndDoubleBufferHeader with the appropriate information. Listing 2-34 illustrates how you can accomplish these tasks.
  2835. Listing 2-34    Setting up double buffers
  2836.  
  2837. CONST
  2838.     kDoubleBufferSize = 4096;                                        {size of each buffer (in bytes)}
  2839. TYPE
  2840.     LocalVars =                                        {variables used by the doubleback procedure}
  2841.     RECORD
  2842.         bytesTotal:                    LongInt;                {total number of samples}
  2843.         bytesCopied:                    LongInt;                {number of samples copied to buffers}
  2844.         dataPtr:                    Ptr;                {pointer to sample to copy}
  2845.     END;
  2846.     LocalVarsPtr = ^LocalVars;
  2847.  
  2848. {This function uses SndPlayDoubleBuffer to play the sound specified.}
  2849. FUNCTION MyDBSndPlay (chan: SndChannelPtr; sndHeader: SoundHeaderPtr): OSErr;
  2850. VAR
  2851.     myVars:                        LocalVars;
  2852.     myDblHeader:                        SndDoubleBufferHeader;
  2853.     myDblBuffer:                        SndDoubleBufferPtr;
  2854.     myStatus:                        SCStatus;
  2855.     myIndex:                        Integer;
  2856.     myErr:                        OSErr;
  2857. BEGIN
  2858.     {Set up myVars with initial information.}
  2859.     myVars.bytesTotal := sndHeader^.length;
  2860.     myVars.bytesCopied := 0;                                                    {no samples copied yet}
  2861.     myVars.dataPtr := Ptr(@sndHeader^.sampleArea[0]);
  2862.                                                         {pointer to first sample}
  2863.     {Set up SndDoubleBufferHeader.}
  2864.     WITH myDblHeader DO
  2865.     BEGIN
  2866.         dbhNumChannels := 1;                                                {one channel}
  2867.         dbhSampleSize := 8;                                                {8-bit samples}
  2868.         dbhCompressionID := 0;                                                {no compression}
  2869.         dbhPacketSize := 0;                                                {no compression}
  2870.         dbhSampleRate := sndHeader^.sampleRate;
  2871.         dbhDoubleBack := @MyDoubleBackProc;
  2872.     END;
  2873.  
  2874.     FOR myIndex := 0 TO 1 DO                                                    {initialize both buffers}
  2875.     BEGIN
  2876.         {Get memory for double buffer.}
  2877.         myDblBuffer := SndDoubleBufferPtr(NewPtr(Sizeof(SndDoubleBuffer) + 
  2878.                                                                      kDoubleBufferSize));
  2879.         IF myDblBuffer = NIL THEN
  2880.         BEGIN
  2881.             MyDBSndPlay := MemError;
  2882.             Exit(MyDBSndPlay);
  2883.         END;
  2884.  
  2885.         myDblBuffer^.dbNumFrames := 0;                                                {no frames yet}
  2886.         myDblBuffer^.dbFlags := 0;                                                {buffer is empty}
  2887.         myDblBuffer^.dbUserInfo[0] := LongInt(@myVars);
  2888.  
  2889.         {Fill buffer with samples.}
  2890.         MyDoubleBackProc(sndChan, myDblBuffer);
  2891.  
  2892.         {Store buffer pointer in header.}
  2893.         myDblHeader.dbhBufferPtr[myIndex] := myDblBuffer;
  2894.     END;
  2895.     {Start the sound playing.}
  2896.     myErr := SndPlayDoubleBuffer(sndChan, @myDblHeader);
  2897.     IF myErr <> noErr THEN
  2898.     BEGIN
  2899.         MyDBSndPlay := myErr;
  2900.         Exit(MyDBSndPlay);
  2901.     END;
  2902.  
  2903.     {Wait for the sound's end by checking the channel status.}
  2904.     REPEAT
  2905.         myErr := SndChannelStatus(chan, sizeof(myStatus), @status);
  2906.     UNTIL NOT myStatus.scChannelBusy;
  2907.  
  2908.     {Dispose double buffer memory.}
  2909.     FOR myIndex := 0 TO 1 DO
  2910.         DisposePtr(Ptr(myDblHeader.dbhBufferPtr[myIndex]));
  2911.  
  2912.     MyDBSndPlay := noErr;
  2913. END;
  2914. The function MyDBSndPlay takes two parameters, a pointer to a sound channel and a pointer to a sound header. For information about obtaining a pointer to a sound header, see “Obtaining a Pointer to a Sound Header” on page 2-57. The MyDBSndPlay function reads the sound header to determine the characteristics of the sound to be played (for example, how many samples are to be sent into the sound channel). Then MyDBSndPlay fills in the fields of the double buffer header, creates two buffers, and starts the sound playing. The doubleback procedure MyDoubleBackProc is defined in the next section.
  2915. Writing a Doubleback Procedure
  2916.  
  2917. The dbhDoubleBack field of a double buffer header specifies the address of a doubleback procedure, an application-defined procedure that is called when the double buffers are switched and the exhausted buffer needs to be refilled. The doubleback procedure should have this format:
  2918. PROCEDURE MyDoubleBackProc (chan: SndChannelPtr; 
  2919.                                     exhaustedBuffer: SndDoubleBufferPtr);
  2920. The primary responsibility of the doubleback procedure is to refill an exhausted buffer of samples and to mark the newly filled buffer as ready for processing. Listing 2-35 illustrates how to define a doubleback procedure. Note that the sound channel pointer passed to the doubleback procedure is not used in this procedure.
  2921. This doubleback procedure extracts the address of its local variables from the dbUserInfo field of the double buffer record passed to it. These variables are used to keep track of how many total bytes need to be copied and how many bytes have been copied so far. Then the procedure copies at most a bufferfull of bytes into the empty buffer and updates several fields in the double buffer record and in the structure containing the local variables. Finally, if all the bytes to be copied have been copied, the buffer is marked as the last buffer.
  2922. Note
  2923. Because the doubleback procedure is called at interrupt time, it cannot make any calls that move memory either directly or indirectly. (Despite its name, the BlockMove procedure does not cause blocks of memory to move or be purged, so you can safely call it in your doubleback procedure, as illustrated in Listing 2-35.)u 
  2924. Listing 2-35    Defining a doubleback procedure
  2925.  
  2926. PROCEDURE MyDoubleBackProc (chan: SndChannelPtr; 
  2927.                                         doubleBuffer: SndDoubleBufferPtr);
  2928. VAR
  2929.     myVarsPtr:                        LocalVarsPtr;
  2930.     myNumBytes:                        LongInt;
  2931. BEGIN
  2932.     {Get pointer to my local variables.}
  2933.     myVarsPtr := LocalVarsPtr(doubleBuffer^.dbUserInfo[0]);
  2934.     
  2935.     {Get number of bytes left to copy.}
  2936.     myNumBytes := myVarsPtr^.bytesTotal - myVarsPtr^.bytesCopied;
  2937.  
  2938.     {If the amount left is greater than double buffer size, limit the number }
  2939.     { of bytes to copy to the size of the buffer.}
  2940.     IF myNumBytes > kDoubleBufferSize THEN
  2941.         myNumBytes := kDoubleBufferSize;
  2942.     
  2943.     {Copy samples to double buffer.}
  2944.     BlockMove(myVarsPtr^.dataPtr, @doubleBuffer^.dbSoundData[0], myNumBytes);
  2945.     
  2946.     {Store number of samples in buffer and mark buffer as ready.}
  2947.     doubleBuffer^.dbNumFrames := myNumBytes;
  2948.     doubleBuffer^.dbFlags := BOR(doubleBuffer^.dbFlags, dbBufferReady);
  2949.     
  2950.     {Update data pointer and number of bytes copied.}
  2951.     myVarsPtr^.dataPtr := Ptr(ORD4(myVarsPtr^.dataPtr) + myNumBytes);
  2952.     myVarsPtr^.bytesCopied := myVarsPtr^.bytesCopied + myNumBytes;
  2953.  
  2954.     {If all samples have been copied, then this is the last buffer.}
  2955.     IF myVarsPtr^.bytesCopied = myVarsPtr^.bytesTotal THEN
  2956.         doubleBuffer^.dbFlags := BOR(doubleBuffer^.dbFlags, dbLastBuffer);
  2957. END;
  2958.  
  2959. Sound Storage Formats
  2960.  
  2961. This section describes in detail the formats of sound resources and sound files, which are the two principal storage formats for sound data on Macintosh computers. In general, an application that uses the services provided by the Sound Manager and the Sound Input Manager to play and record sounds does not need to know how the sound data is organized in memory or on disk. For some special purposes, however, you might need the information in this section.
  2962. Sound Resources
  2963.  
  2964. A sound resource is a resource of type 'snd ' that contains sound commands and possibly also sound data. Sound resources are widely used by Macintosh applications that produce sounds. These resources provide a simple and portable way for you to incorporate sounds into your application. For example, the sounds that a user can select in the Sound control panel as the system alert sound are stored in the System file as 'snd ' resources.
  2965. There are two types of 'snd ' resources, known as format 1 and format 2. Figure 2-4 illustrates the structures of both kinds of 'snd ' resources.
  2966. Figure 2-4    The structure of 'snd ' resources
  2967.  
  2968. IMPORTANT
  2969. The format 2 'snd ' resource is obsolete. Your application should create only format 1 'snd ' resources. The format 2 'snd ' resource was designed for use by HyperCard and can be used with sampled-sound data only.s
  2970. Resource IDs for 'snd ' resources in the range 0 to 8191 are reserved for use by Apple Computer, Inc. The 'snd ' resources numbered 1 through 4 are defined to be the standard system alert sounds, although more recent versions of system software have included more standard system alert sounds.
  2971. When a sound command contained in an 'snd ' resource has associated sound data, the high bit of the command is set. This changes the meaning of the param2 field of the command from a pointer to a location in RAM to an offset value that specifies the offset in bytes from the resource’s beginning to the location of the associated sound data (such as a sampled sound header). Figure 2-5 illustrates the location of this data offset bit.
  2972. Figure 2-5    The location of the data offset bit
  2973.  
  2974. The offset bit is used only by sound commands that are stored in sound resources of type 'snd ' and that have associated sound data (that is, sampled-sound or wave-table data).
  2975. You can use a constant to access that flag.
  2976. CONST
  2977.     dataOffsetFlag                        = $8000;             {sound command data offset bit}
  2978. If the dataOffsetFlag bit is not set, param2 is interpreted instead as a pointer to the location in memory (outside the sound resource) where the data is located.
  2979. The first few bytes of the resource contain 'snd ' header information and are a different size for each format. An audio data type specified in a format 1 'snd ' requires 6 bytes. The number of data types multiplied by 6 is added to this offset. The number of commands multiplied by 8 bytes, the size of a sound command, is added to the offset.
  2980. The Format 1 Sound Resource
  2981.  
  2982. Figure 2-4 shows the fields of a format 1 'snd ' resource. A format 1 'snd ' resource header contains information about the format of the resource (namely, 1), the data type, and the initialization options for that data type. A format 1 'snd ' resource contains sound commands and might also contain the actual sound data for wave-table sounds or sampled sounds. Note that if a sound resource includes sampled-sound data, then part of the sound data section is devoted to a sound header that describes the sampled-sound data in the remainder of the sound data section.
  2983. If an 'snd ' resource specifies a data type, it can supply an initialization option in the field immediately following the type. You specify the number of commands in the resource in the number of sound commands field. The sound commands follow, in the order in which they should be sent to the sound channel.
  2984. The format 1 'snd ' resource might contain only a sequence of commands describing a sound. In this case, the number of data types should be 0, and there should be no data type specification or initialization option in the 'snd ' resource. This allows the 'snd ' resource to be used with any kind of sound data.
  2985. Listing 2-36 shows the output of the MPW tool DeRez when applied to the 'snd ' resource with resource ID 1 contained in the System file.
  2986. Listing 2-36    A format 1 'snd ' resource
  2987.  
  2988. data 'snd ' (1, "Simple Beep", purgeable) {
  2989.     /*the sound resource header*/
  2990.     $"0001"                /*format type*/
  2991.     $"0001"                /*number of data types*/
  2992.     $"0001"                /*square-wave data*/
  2993.     $"00000000"                /*initialization option*/
  2994.     /*the sound commands*/
  2995.     $"001B"                /*number of sound commands (27)*/
  2996.     $"002C"                /*command 1--timbreCmd 090 000*/
  2997.     $"005A00000000"
  2998.     $"002B"                /*command 2--ampCmd  224 000*/
  2999.     $"00E000000000"
  3000.     $"002A"                /*command 3--freqCmd 000 069*/
  3001.     $"000000000045"
  3002.     $"000A"                /*command 4--waitCmd 040 000*/
  3003.     $"002800000000"
  3004.     $"002B"                /*command 5--ampCmd  200 000*/
  3005.     $"00C800000000"
  3006.     /*commands 6 through 26 are omitted; they are */
  3007.     /* alternating pairs of waitCmd and ampCmd commands */
  3008.     /* where the first parameter of ampCmd has the */
  3009.     /* values 192, 184, 176, 168, 160, 144, 128, 96, */
  3010.     /* 64, and 32*/
  3011.     $"002B"                /*command 27--ampCmd  000 000*/
  3012.     $"000000000000"
  3013. };
  3014. As you can see, the Simple Beep is actually a rather sophisticated sound, in which the loudness (or amplitude) of the beep gradually decreases from an initial value of 224 to 0.
  3015. Notice that the sound shown in Listing 2-36 is defined using square-wave data and is completely determined by a sequence of specific commands. (“Play an A at loudness 224, wait 20 milliseconds, play it at loudness 200....”) Often, an 'snd ' resource consists only of a single sound command (usually the bufferCmd command) together with data that describes a sampled sound to be played. Listing 2-37 shows an example like this.
  3016. Listing 2-37     A format 1 'snd ' resource containing sampled-sound data
  3017.  
  3018. data 'snd ' (19068, "hello daddy", purgeable) {
  3019.     /*the sound resource header*/
  3020.     $"0001"                    /*format type*/
  3021.     $"0001"                    /*number of data types*/
  3022.     $"0005"                    /*sampled-sound data*/
  3023.     $"00000080"                    /*initialization option: initMono*/
  3024.     /*the sound commands*/
  3025.     $"0001"                    /*number of sound commands that follow (1)*/
  3026.     $"8051"                    /*command 1--bufferCmd*/
  3027.     $"0000"                    /*param1 = 0*/
  3028.     $"00000014"                    /*param2 = offset to sound header (20 bytes)*/
  3029.     /*the sampled sound header*/
  3030.     $"00000000"                    /*pointer to data (it follows immediately)*/
  3031.     $"00000BB8"                    /*number of bytes in sample (3000 bytes)*/
  3032.     $"56EE8BA3"                    /*sampling rate of this sound (22 kHz)*/
  3033.     $"000007D0"                    /*starting of the sample's loop point*/
  3034.     $"00000898"                    /*ending of the sample's loop point*/
  3035.     $"00"                    /*standard sample encoding*/
  3036.     $"3C"                    /*baseFrequency at which sample was taken*/
  3037.                         /*the sampled-sound data*/
  3038.     $"80 80 81 81 81 81 81 81 80 80 80 80 80 81 82 82"
  3039.     $"82 83 82 82 81 80 80 7F 7F 7F 7E 7D 7D 7D 7C 7C"
  3040.     $"7C 7C 7D 7D 7D 7D 7E 7F 80 80 81 81 82 82 83 83"
  3041.     $"83 83 82 81 81 80 80 81 81 81 81 81 82 81 81 80"
  3042.     $"80 80 81 81 81 83 83 83 82 81 81 80 7F 7E 7D 7D"
  3043.     $"7F 7F 7F 7F 7E 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 80"
  3044.     /*rest of data omitted in this example*/
  3045. };
  3046. This 'snd ' resource indicates that the sound is defined using sampled-sound data. The resource includes a call to a single sound command, the bufferCmd command. The offset bit of the command number is set to indicate that the sound data is contained in the resource itself. Following the command and its two parameters is the sampled sound header, the first part of which contains important information about the sample. The second parameter to the bufferCmd command indicates the offset from the beginning of the resource to the sampled sound header, in this case 20 bytes. After the sound commands, this resource includes a sampled sound header, which includes the sampled-sound data. The format of a sampled sound header is described in “Sound Header Records” on page 2-104.
  3047. For compressed sound data, the sampled sound header is replaced by a compressed sampled sound header. Listing 2-38 illustrates the structure of an 'snd ' resource that contains compressed sound data.
  3048. Listing 2-38    An 'snd ' resource containing compressed sound data
  3049.  
  3050. data 'snd ' (9004, "Raisa's Cry", purgeable) {
  3051.     /*the sound resource header*/
  3052.     $"0001"                /*format type*/
  3053.     $"0001"                /*number of data types*/
  3054.     $"0005"                /*first data type*/
  3055.     $"00000380"                /*initialization option: initMACE3 + initMono*/
  3056.     /*the sound command*/
  3057.     $"0001"                /*number of sound commands that follow (1)*/
  3058.     $"8051"                /*cmd: bufferCmd*/
  3059.     $"0000"                /*param1: unused*/
  3060.     $"00000014"                /*param2: offset to sound header (20 bytes)*/
  3061.     /*the compressed sampled sound header*/
  3062.     $"00000000"                /*pointer to data (it follows immediately)*/
  3063.     $"00000001"                /*number of channels in sample*/
  3064.     $"56EE8BA3"                /*sampling rate of this sound (22 kHz)*/
  3065.     $"00000000"                /*starting of the sample's loop point; not used*/
  3066.     $"00000000"                /*ending of the sample's loop point; not used*/
  3067.     $"FE"                /*compressed sample encoding*/
  3068.     $"00"                /*baseFrequency; not used*/
  3069.     $"00006590"                /*number of frames in sample (26,000)*/
  3070.     $"400DADDD1745D145826B"                                
  3071.                     /*AIFFSampleRate (22 kHz in extended type)*/
  3072.     $"00000000"                /*markerChunk; NIL for 'snd ' resource*/
  3073.     $"4D414333"                /*format; MACE 3:1 compression*/
  3074.     $"00000000"                /*futureUse2; NIL for 'snd ' resource*/
  3075.     $"00000000"                /*stateVars; NIL for 'snd ' resource*/
  3076.     $"00000000"                /*leftOverBlockPtr; not used here*/
  3077.     $"FFFF"                /*compressionID, -1 means use format field*/
  3078.     $"0010"                /*packetSize, packetSize for 3:1 is 16 bits*/
  3079.     $"0000"                /*snthID is 0*/
  3080.     $"0008"                /*sampleSize, sound was 8-bit before processing*/
  3081.     $"2F 85 81 32 64 87 33 86"                                        /*the compressed sound data*/
  3082.     $"6F 48 6D 65 72 6B 82 88"
  3083.     $"91 FE 8D 8E 86 4E 7C E9"
  3084.     $"6F 6D 71 70 7E 79 4F 83"
  3085.     $"59 8F 8F 65"                    /*rest of data omitted in this example*/
  3086. };
  3087. This resource has the same general structure as the 'snd ' resource illustrated in Listing 2-36. The principal difference is that the standard sound header is replaced by the compressed sound header. This example resource specifies a monophonic sound compressed by using the 3:1 compression algorithm. A multichannel compressed sound’s data would be interleaved on a packet basis. See “Compressed Sound Header Records” beginning on page 2-108 for a complete explanation of the compressed sound header.
  3088. As you’ve seen, it is not always necessary to specify 'snd ' resources by listing the raw data stream contained in them; indeed, for certain types of format 1 'snd ' resources, it can be easier to supply a resource specification like the one given in Listing 2-39.
  3089. Listing 2-39    A resource specification
  3090.  
  3091. resource 'snd ' (9000, "Nathan's Beep", purgeable) {
  3092.     FormatOne {
  3093.         {    /*array of data types: 1 element*/
  3094.         /*[1]*/
  3095.         squareWaveSynth, 0
  3096.         }
  3097.     },
  3098.     {        /*array SoundCmnds: 3 elements*/
  3099.     /*[1]*/ noData, timbreCmd {90},
  3100.     /*[2]*/ noData, freqDurationCmd {480, $00000045},
  3101.     /*[3]*/ noData, quietCmd {},
  3102.         },
  3103.     {        /*array DataTables: 0 elements*/
  3104.     };
  3105. };
  3106. When you pass a handle to this resource to the SndPlay function, three commands are executed by the Sound Manager: a timbreCmd command, a freqDurationCmd command, and a quietCmd command. The sound specified in Listing 2-39 is just like the Simple Beep, except that there is no gradual reduction in the loudness. Listing 2-40 shows a resource specification for the Simple Beep.
  3107. Listing 2-40    A resource specification for the Simple Beep
  3108.  
  3109. resource 'snd ' (9001, "Copy of Simple Beep", purgeable) {
  3110.     FormatOne {
  3111.         {    /*array of data types: 1 element*/
  3112.             /*[1]*/
  3113.             squareWaveSynth, 0
  3114.         }
  3115.     },
  3116.     {    /*array SoundCmnds: 27 elements*/
  3117.         /*[1]*/                nodata, timbreCmd {90},
  3118.         /*[2]*/                nodata, ampCmd {224},
  3119.         /*[3]*/                nodata, freqCmd {69},
  3120.         /*[4]*/                nodata, waitCmd {40},
  3121.         /*[5]*/                nodata, ampCmd {200},
  3122.         /*[6]*/                nodata, waitCmd {40},
  3123.         /*[7]*/                nodata, ampCmd {192},
  3124.         /*[8]*/                nodata, waitCmd {40},
  3125.         /*[9]*/                nodata, ampCmd {184},
  3126.         /*[10]*/                nodata, waitCmd {40},
  3127.         /*[11]*/                nodata, ampCmd {176},
  3128.         /*[12]*/                nodata, waitCmd {40},
  3129.         /*[13]*/                nodata, ampCmd {168},
  3130.         /*[14]*/                nodata, waitCmd {40},
  3131.         /*[15]*/                nodata, ampCmd {160},
  3132.         /*[16]*/                nodata, waitCmd {40},
  3133.         /*[17]*/                nodata, ampCmd {144},
  3134.         /*[18]*/                nodata, waitCmd {40},
  3135.         /*[19]*/                nodata, ampCmd {128},
  3136.         /*[20]*/                nodata, waitCmd {40},
  3137.         /*[21]*/                nodata, ampCmd {96},
  3138.         /*[22]*/                nodata, waitCmd {40},
  3139.         /*[23]*/                nodata, ampCmd {64},
  3140.         /*[24]*/                nodata, waitCmd {40},
  3141.         /*[25]*/                nodata, ampCmd {32},
  3142.         /*[26]*/                nodata, waitCmd {40},
  3143.         /*[27]*/                nodata, ampCmd {0},
  3144.     },
  3145.     {    /*array DataTables: 0 elements*/
  3146.     }
  3147. };
  3148. The Format 2 Sound Resource 
  3149.  
  3150. The SndPlay function can also play format 2 'snd ' resources, which are designed for use only with sampled sounds. The SndPlay function supports this format by automatically opening a sound channel and using the bufferCmd command to send the data contained in the resource to the channel.
  3151. Figure 2-4 illustrates the fields of a format 2 'snd ' resource. The reference count field is for your application’s use and is not used by the Sound Manager. The number of sound commands field and the sound command fields are the same as described in a format 1 resource. The last field of this resource contains the sampled sound. The first command should be either a soundCmd command or bufferCmd command with the data offset bit set in the command to specify the location of this sampled sound header.
  3152. Listing 2-41 shows a resource specification that illustrates the structure of a format 2 'snd ' resource.
  3153. Listing 2-41    A format 2 'snd ' resource
  3154.  
  3155. data 'snd ' (9003, "Pig Squeal", purgeable) {
  3156.     /*the sound resource header*/
  3157.     $"0002"                    /*format type*/
  3158.     $"0000"                    /*reference count for application's use*/
  3159.     /*the sound command*/
  3160.     $"0001"                    /*number of sound commands that follow (1)*/
  3161.     $"8051"                    /*command 1--bufferCmd*/
  3162.     $"0000"                    /*param1 = 0*/
  3163.     $"0000000E"                    /*param2 = offset to sound header (14 bytes)*/
  3164.     /*the sampled sound header*/
  3165.     $"00000000"                    /*pointer to data (it follows immediately)*/
  3166.     $"00000BB8"                    /*number of bytes in sample (3000 bytes)*/
  3167.     $"56EE8BA3"                    /*sampling rate of this sound (22 kHz)*/
  3168.     $"000007D0"                    /*starting of the sample's loop point*/
  3169.     $"00000898"                    /*ending of the sample's loop point*/
  3170.     $"00"                    /*standard sample encoding*/
  3171.     $"3C"                    /*baseFrequency at which sample was taken*/
  3172.     $"80 80 81 82 84 87 93 84"                                        /*the sampled-sound data*/
  3173.     $"6F 68 6D 65 72 7B 82 88"
  3174.     $"91 8E 8D 8F 86 7E 7C 79"
  3175.     $"6F 6D 71 70 70 79 7F 81"
  3176.     $"89 8F 8D 8B"                    /*rest of data omitted in this example*/
  3177. };
  3178. Note
  3179. Remember that format 2 'snd ' resources are obsolete. You should create only format 1 'snd ' resources.u
  3180. Sound Files
  3181.  
  3182. This section describes in detail the structure of AIFF and AIFF-C files. Both of these types of sound files are collections of chunks that define characteristics of the sampled sound or other relevant data about the sound.
  3183. Note
  3184. Note
  3185. Most applications only need to read AIFF and AIFF-C files or to record sampled-sound data directly to them. You can both play and record AIFF and AIFF-C files without knowing the details of the AIFF and AIFF-C file formats, as explained in the chapter “Introduction to Sound on the Macintosh” in this book. Thus, the information in this section is for advanced programmers only.u
  3186. Currently, the AIFF and AIFF-C specifications include the following chunk types.
  3187. Chunk type    Description    
  3188. Form Chunk    Contains information about the format of an AIFF or AIFF-C file and contains all the other chunks of such a file.    
  3189. Format Version Chunk    Contains an indication of the version of the AIFF-C specification according to which this file is structured (AIFF-C only).    
  3190. Common Chunk    Contains information about the sampled sound such as the sampling rate and sample size.    
  3191. Sound Data Chunk    Contains the sample frames that comprise the sampled sound.    
  3192. Marker Chunk    Contains markers that point to positions in the sound data.    
  3193. Comments Chunk    Contains comments about markers in the file.    
  3194. Sound Accelerator Chunk    Contains information intended to allow applications to accelerate the decompression of compressed audio data.    
  3195. Instrument Chunk    Defines basic parameters that an instrument (such as a sampling keyboard) can use to play back the sound data.    
  3196. MIDI Data Chunk    Contains MIDI data.    
  3197. Audio Recording Chunk    Contains information pertaining to audio recording devices.    
  3198. Application Specific Chunk    Contains application-specific information.    
  3199. Name Chunk    Contains the name of the sampled sound.    
  3200. Author Chunk    Contains one or more names of the authors (or creators) of the sampled sound.    
  3201. Copyright Chunk    Contains a copyright notice for the sampled sound.    
  3202. Annotation Chunk    Contains a comment.    
  3203.  
  3204. The following sections document the four principal kinds of chunks that can occur in AIFF and AIFF-C files.
  3205. Chunk Organization and Data Types
  3206.  
  3207. An AIFF or AIFF-C file contains several different types of chunks. For example, there is a Common Chunk that specifies important parameters of the sampled sound, such as its size and sample rate. There is also a Sound Data Chunk that contains the actual audio samples. A chunk consists of some header information followed by some data. The header information consists of a chunk ID number and a number that indicates the size of the chunk data. In general, therefore, a chunk has the structure shown in Figure 2-6.
  3208. Figure 2-6    The general structure of a chunk
  3209.  
  3210. The header information of a chunk has this structure:
  3211. TYPE ChunkHeader =
  3212. RECORD
  3213.     ckID:            ID;                {chunk type ID}
  3214.     ckSize:            LongInt;                {number of bytes of data}
  3215. END;
  3216. The ckID field specifies the chunk type. An ID is a 32-bit concatenation of any four printable ASCII characters in the range ' ' (space character, ASCII value $20) through '~' (ASCII value $7E). Spaces cannot precede printing characters, but trailing spaces are allowed. Control characters are not allowed. You can specify values for the four types of chunks described later by using these constants:
  3217. CONST
  3218.     FormID                        = 'FORM';                {ID for Form Chunk}
  3219.     FormatVersionID                        = 'FVER';                {ID for Format Version Chunk}
  3220.     CommonID                        = 'COMM';                {ID for Common Chunk}
  3221.     SoundDataID                        = 'SSND';                {ID for Sound Data Chunk}
  3222. The ckSize field specifies the size of the data portion of a chunk and does not include the length of the chunk header information.
  3223. The Form Chunk
  3224.  
  3225. The chunks that define the characteristics of a sampled sound and that contain the actual sound data are grouped together into a container chunk, known as the Form Chunk. The Form Chunk defines the type and size of the file and holds all remaining chunks in the file. The chunk ID for this container chunk is 'FORM'. 
  3226. A chunk of type 'FORM' has this structure:
  3227. TYPE ContainerChunk =
  3228. RECORD
  3229.     ckID:                ID;                {'FORM'}
  3230.     ckSize:                LongInt;                {number of bytes of data}
  3231.     formType:                ID;                {type of file}
  3232. END;
  3233. For a Form Chunk, the ckSize field contains the size of the data portion of this chunk. Note that the data portion of a Form Chunk is divided into two parts, formType and the rest of the chunks of the file, which follow the formType field. These chunks are called local chunks because their chunk IDs are local to the Form Chunk.
  3234. The local chunks can occur in any order in a sound file. As a result, your application should be designed to get a local chunk, identify it, and then process it without making any assumptions about what kind of chunk it is based on its order in the Form Chunk.
  3235. The formType field of the Form Chunk specifies the format of the file. For AIFF files, formType is 'AIFF'. For AIFF-C files, formType is 'AIFC'. Note that this type might not be the same as the operating-system type with which the File Manager identifies the file. In particular, a file of operating-system type 'AIFC' might be formatted as an AIFF file.
  3236. The Format Version Chunk
  3237.  
  3238. One difference between the AIFF and AIFF-C file formats is that files of type AIFF-C contain a Format Version Chunk and files of type AIFF do not. The Format Version Chunk contains a timestamp field that indicates when the format version of this AIFF-C file was defined. This in turn indicates what format rules this file conforms to and allows you to ensure that your application can handle a particular AIFF-C file. Every AIFF-C file must contain one and only one Format Version Chunk.
  3239. In AIFF-C files, a Format Version Chunk has this structure:
  3240. TYPE FormatVersionChunk =
  3241. RECORD
  3242.     ckID:                ID;                {'FVER'}
  3243.     ckSize:                LongInt;                {4}
  3244.     timestamp:                LongInt;                {date of format version}
  3245. END;
  3246. Note
  3247. In AIFF files, there is no Format Version Chunk.u
  3248. The timestamp field indicates when the format version for this kind of file was created. The value indicates the number of seconds since January 1, 1904, following the normal time conventions used by the Macintosh Operating System. (See the chapter on date and time utilities in Inside Macintosh: Operating System Utilities for several routines that allow you to manipulate time stamps.)
  3249. You should not confuse the format version time stamp with the creation date of the file. The format version time stamp indicates the time of creation of the version of the format according to which this file is structured. Because Apple defines the formats of AIFF-C files, only Apple can change this value. The current version is defined by a constant:
  3250. CONST
  3251.     AIFCVersion1                    = $A2805140;                    {May 23, 1990, 2:40 p.m.}
  3252. The Common Chunk
  3253.  
  3254. Every AIFF and AIFF-C file must contain a Common Chunk that defines some fundamental characteristics of the sampled sound contained in the file. Note that the format of the Common Chunk is different for AIFF and AIFF-C files. As a result, you need to determine the type of file format (by inspecting the formType field of the Form Chunk) before reading the Common Chunk.
  3255. For AIFF files, the Common Chunk has this structure:
  3256. TYPE CommonChunk =
  3257. RECORD
  3258.     ckID:                        ID;                {'COMM'}
  3259.     ckSize:                        LongInt;                {size of chunk data}
  3260.     numChannels:                        Integer;                {number of channels}
  3261.     numSampleFrames:                        LongInt;                {number of sample frames}
  3262.     sampleSize:                        Integer;                {number of bits per sample}
  3263.     sampleRate:                        Extended;                {number of frames per second}
  3264. END;
  3265. For AIFF-C files, the Common Chunk has this structure:
  3266. TYPE ExtCommonChunk =
  3267. RECORD
  3268.     ckID:                        ID;                {'COMM'}
  3269.     ckSize:                        LongInt;                {size of chunk data}
  3270.     numChannels:                        Integer;                {number of channels}
  3271.     numSampleFrames:                        LongInt;                {number of sample frames}
  3272.     sampleSize:                        Integer;                {number of bits per sample}
  3273.     sampleRate:                        Extended;                {number of frames per second}
  3274.     compressionType:                        ID;                {compression type ID}
  3275.     compressionName:                        PACKED ARRAY[0..0] OF Byte;
  3276.                                             {compression type name}
  3277. END;
  3278. The fields that exist in both types of Common Chunk have the following meanings:
  3279. The numChannels field of both types of Common Chunk indicate the number of audio channels contained in the sampled sound. A value of 1 indicates monophonic sound, a value of 2 indicates stereo sound, a value of 4 indicates four-channel sound, and so forth. Any number of audio channels may be specified. The actual sound data is stored elsewhere, in the Sound Data Chunk.
  3280. The numSampleFrames field indicates the number of sample frames in the Sound Data Chunk. Note that this field contains the number of sample frames, not the number of bytes of data and not the number of sample points. For noncompressed sound data, the total number of sample points in the file is numChannels * numSampleFrames. (For more information on sample points, see “Sampled-Sound Data” on page 2-9.)
  3281. The sampleSize field indicates the number of bits in each sample point of noncompressed sound. Although the field can contain any integer from 1 to 32, the Sound Manager currently supports only 8- and 16-bit sound. For compressed sound data, this field indicates the number of bits per sample in the original sound data, before compression.
  3282. The sampleRate field contains the sample rate at which the sound is to be played back, in sample frames per second. For a list of common sample rates, see Table 2-1 on page 2-16.
  3283. An AIFF-C Common Chunk includes two fields that describe the type of compression (if any) used on the audio data. The compressionType field contains the type of the compression algorithm, if any, used on the sound data. Here are the currently available compression types and their associated compression names:
  3284. CONST
  3285.     {compression types}
  3286.     NoneType                                = 'NONE';
  3287.     ACE2Type                                = 'ACE2';
  3288.     ACE8Type                                = 'ACE8';
  3289.     MACE3Type                                = 'MAC3';
  3290.     MACE6Type                                = 'MAC6';
  3291. You can define your own compression types, but you should register them with Apple.
  3292. Finally, the compressionName field contains a human-readable name for the compression algorithm ID specified in the compressionType field. Compression names for Apple-supplied codecs are defined by constants:
  3293. CONST
  3294.     {compression names}
  3295.     NoneName                                = 'not compressed';
  3296.     ACE2to1Name                                = 'ACE 2-to-1';
  3297.     ACE8to3Name                                = 'ACE 8-to-3';
  3298.     MACE3to1Name                                = 'MACE 3-to-1';
  3299.     MACE6to1Name                                = 'MACE 6-to-1';
  3300. This string is useful when putting up alert boxes (perhaps because a necessary decompression routine is missing). Pad the end of this array with a byte having the value 0 if the length of this array is not an even number (but do not include the pad byte in the count).
  3301. The Sound Data Chunk
  3302.  
  3303. The Sound Data Chunk contains the actual sample frames that make up the sampled sound. The Sound Data Chunk has this structure:
  3304. TYPE SoundDataChunk =
  3305. RECORD
  3306.     ckID:                ID;                {'SSND'}
  3307.     ckSize:                LongInt;                {size of chunk data}
  3308.     offset:                LongInt;                {offset to sound data}
  3309.     blockSize:                LongInt;                {size of alignment blocks}
  3310. END;
  3311. The offset field indicates an offset (in bytes) to the beginning of the first sample frame in the chunk data. Most applications do not need to use the offset field and should set it to 0.
  3312. The blockSize field contains the size (in bytes) of the blocks to which the sound data is aligned. This field is used in conjunction with the offset field for aligning sound data to blocks. As with the offset field, most applications do not need to use the blockSize field and should set it to 0.
  3313. The sampled-sound data follows the blockSize field. For information on the format of sampled-sound data, see “Sampled-Sound Data” on page 2-9.
  3314. Note
  3315. The Sound Data Chunk is required unless the numSampleFrames field in the Common Chunk is 0. A maximum of one Sound Data Chunk can appear in an AIFF or AIFF-C file.u 
  3316. Format of Entire Sound Files
  3317.  
  3318. Figure 2-7 illustrates an AIFF-C file that contains approximately 4.476 seconds of 8-bit monophonic sound data sampled at 22 kHz. The sound data is not compressed. Note that the number of sample frames in this example is odd, forcing a pad byte to be inserted after the sound data. This pad byte is not reflected in the ckSize field of the Sound Data Chunk, which means that special processing is required to correctly determine the actual chunk size.
  3319. On a Macintosh computer, the Form Chunk (and hence all the other chunks in an AIFF or AIFF-C file) is stored in the data fork of the file. The file type of an AIFF format file is 'AIFF', and the file type of an AIFF-C format file is 'AIFC'. Macintosh applications should not store any information in the resource fork of an AIFF or AIFF-C file because that information might not be preserved by other applications that edit sound files.
  3320. Figure 2-7    A sample AIFF-C file
  3321.  
  3322. Every Form Chunk must contain a Common Chunk, and every AIFF-C file must contain a Format Version Chunk. In addition, if the sampled sound has a length greater than 0, there must be a Sound Data Chunk in the Form Chunk. All other chunk types are optional. Your application should be able to read all the required chunks if it uses AIFF or AIFF-C files, but it can choose to ignore any of the optional chunks.
  3323. When reading AIFF or AIFF-C files, you should keep the following points in mind:
  3324. n    Remember that the local chunks in an AIFF or AIFF-C file can occur in any order. An application that reads these types of files should be designed to get a chunk, identify it, and then process it without making any assumptions about what kind of chunk it is based on its order.
  3325. n    If your application allows modification of a chunk, then it must also update other chunks that might be based on the modified chunk. However, if there are chunks in the file that your application does not recognize, you must discard those unrecognized chunks. Of course, if your application is simply copying the AIFF or AIFF-C file without any modification, you should copy the unrecognized chunks, too.
  3326. n    You can get the clearest indication of the number of sample frames contained in an AIFF or AIFF-C file from the numSampleFrames parameter in the Common Chunk, not from the ckSize parameter in the Sound Data Chunk. The ckSize parameter is padded to include the fields that follow it, but it does not include the byte with a value of 0 at the end if the total number of sound data bytes is odd.
  3327. n    Remember that each chunk must contain an even number of bytes. Chunks whose total contents would yield an odd number of bytes must have a pad byte with a value of 0 added at the end of the chunk. This pad byte is not included in the ckSize field.
  3328. n    Remember that the ckSize field of any chunk does not include the first 8 bytes of the chunk (which specify the chunk type).
  3329.  
  3330. Sound Manager Reference
  3331.  
  3332. This section describes the constants, data structures, and routines provided by the Sound Manager. It also describes the format of data stored in sound resources and files that the Sound Manager can play.
  3333. The section “Constants” describes the constants defined by the Sound Manager that you can use to specify channel initialization parameters and sound commands. It also lists the sound attributes selector for the Gestalt function and the returned bit numbers. See the section “Summary of the Sound Manager” on page 2-157 for a list of all the constants defined by the Sound Manager.
  3334. The section “Data Structures” beginning on page 2-99 describes the Pascal data structures for all of the Sound Manager records that applications can use, including sound commands, sound channels, and sound headers.
  3335. The section “Sound Manager Routines” beginning on page 2-119 describes the routines that allow you to play sounds, manage sound channels, and obtain sound-related information. That section also includes information on routines that give you low-level control over sound output.
  3336. The section “Application-Defined Routines” beginning on page 2-151 describes callback procedures and completion routines that your application might need to define.
  3337. The section “Resources” beginning on page 2-154 describes the organization of format 1 and format 2 'snd ' resources.
  3338. Constants
  3339.  
  3340. This section describes the constants that you can use to specify channel initialization parameters, sound commands, and chunk IDs. It also lists the Gestalt function sound attributes selector and the returned bit numbers. All other constants defined by the Sound Manager are described at the appropriate location in this chapter. (For example, the constants that you can use to specify sound data types are described in connection with the SndNewChannel function beginning on page 2-127.)
  3341. Gestalt Selector and Response Bits
  3342.  
  3343. You can pass the gestaltSoundAttr selector to the Gestalt function to determine information about the sound capabilities of a Macintosh computer.
  3344. CONST
  3345.     gestaltSoundAttr                                    = 'snd ';                {sound attributes selector}
  3346. The Gestalt function returns information by setting or clearing bits in the response parameter. The bits currently used are defined by constants. Note that most of these bits provide information about the built-in hardware only.
  3347. IMPORTANT
  3348. Bits 7 through 12 are not defined for versions of the Sound Manager prior to version 3.0.s
  3349. CONST
  3350.     gestaltStereoCapability                                    = 0;            {built-in hw can play stereo sounds}
  3351.     gestaltStereoMixing                                    = 1;            {built-in hw mixes stereo to mono}
  3352.     gestaltSoundIOMgrPresent                                    = 3;            {sound input routines available}
  3353.     gestaltBuiltInSoundInput                                    = 4;            {built-in input hw available}
  3354.     gestaltHasSoundInputDevice                                    = 5;            {sound input device available}
  3355.     gestaltPlayAndRecord                                    = 6;            {built-in hw can play while recording}
  3356.     gestalt16BitSoundIO                                     = 7;            {built-in hw can handle 16-bit data}
  3357.     gestaltStereoInput                                     = 8;            {built-in hw can record stereo sounds}
  3358.     gestaltLineLevelInput                                     = 9;            {built-in input hw needs line level}
  3359.     gestaltSndPlayDoubleBuffer                                    = 10;            {play from disk routines available}
  3360.     gestaltMultiChannels                                    = 11;            {multiple channels of sound supported}
  3361.     gestalt16BitAudioSupport                                     = 12;            {16-bit audio data supported}
  3362. Constant descriptions
  3363. gestaltStereoCapability
  3364. Set if the built-in sound hardware is able to produce stereo sounds.
  3365. gestaltStereoMixing
  3366. Set if the built-in sound hardware mixes both left and right channels of stereo sound into a single audio signal for the internal speaker.
  3367. gestaltSoundIOMgrPresent
  3368. Set if the Sound Input Manager is available.
  3369. gestaltBuiltInSoundInput
  3370. Set if a built-in sound input device is available.
  3371. gestaltHasSoundInputDevice
  3372. Set if a sound input device is available. This device can be either built-in or external.
  3373. gestaltPlayAndRecord
  3374. Set if the built-in sound hardware is able to play and record sounds simultaneously. If this bit is clear, the built-in sound hardware can either play or record, but not do both at once. This bit is valid only if the gestaltBuiltInSoundInput bit is set, and it applies only to any built-in sound input and output hardware.
  3375. gestalt16BitSoundIO
  3376. Set if the built-in sound hardware is able to play and record 16-bit samples. This indicates that built-in hardware necessary to handle 16-bit data is available.
  3377. gestaltStereoInput
  3378. Set if the built-in sound hardware can record stereo sounds.
  3379. gestaltLineLevelInput
  3380. Set if the built-in sound input port requires line level input.
  3381. gestaltSndPlayDoubleBuffer
  3382. Set if the Sound Manager supports the play-from-disk routines.
  3383. gestaltMultiChannels
  3384. Set if the Sound Manager supports multiple channels of sound.
  3385. gestalt16BitAudioSupport
  3386. Set if the Sound Manager can handle 16-bit audio data. This indicates that software necessary to handle 16-bit data is available.
  3387. Note
  3388. For complete information about the Gestalt function, see the chapter “Gestalt Manager” in Inside Macintosh: Operating System Utilities.u
  3389. Channel Initialization Parameters
  3390.  
  3391. You can use the following constants to specify initialization parameters for a sound channel. You need to specify initialization parameters when you call SndNewChannel.
  3392. CONST
  3393.     initChanLeft                                = $0002;                {left stereo channel}
  3394.     initChanRight                                = $0003;                {right stereo channel}
  3395.     waveInitChannel0                                = $0004;                {wave-table channel 0}
  3396.     waveInitChannel1                                = $0005;                {wave-table channel 1}
  3397.     waveInitChanne12                                = $0006;                {wave-table channel 2}
  3398.     waveInitChannel3                                = $0007;                {wave-table channel 3}
  3399.     initMono                                = $0080;                {monophonic channel}
  3400.     initStereo                                = $00C0;                {stereo channel}
  3401.     initMACE3                                = $0300;                {3:1 compression}
  3402.     initMACE6                                = $0400;                {6:1 compression}
  3403.     initNoInterp                                = $0004;                {no linear interpolation}
  3404.     initNoDrop                                = $0008;                {no drop-sample conversion}
  3405. Constant descriptions
  3406. initChanLeft    Play sounds through the left channel of the Macintosh audio jack.
  3407. initChanRight    Play sounds through the right channel of the Macintosh audio jack.
  3408. waveInitChannel0
  3409. Play sounds through the first wave-table channel.
  3410. waveInitChannel1
  3411. Play sounds through the second wave-table channel.
  3412. waveInitChannel2
  3413. Play sounds through the third wave-table channel.
  3414. waveInitChannel3
  3415. Play sounds through the fourth wave-table channel.
  3416. initMono    Play the same sound through both channels of the Macintosh audio jack and the internal speaker. This is the default channel mode.
  3417. initStereo    Play stereo sounds through both channels of the Macintosh audio jack and the internal speaker. Note that some machines cannot play stereo sounds.
  3418. initMACE3    Assume that the sounds to be played through the channel are MACE 3:1 compressed. The SndNewChannel function uses this information to help determine whether it can allocate a new sound channel. A noncompressed sound plays normally, even through a channel that has been initialized for MACE.
  3419. initMACE6    Assume that the sounds to be played through the channel are MACE 6:1 compressed. The SndNewChannel function uses this information to help determine whether it can allocate a new sound channel. A noncompressed sound plays normally, even through a channel that has been initialized for MACE.
  3420. initNoInterp    Do not use linear interpolation to smooth a sound played back at a different sample rate from the sound’s recorded sample rate. Using the initNoInterp initialization parameter decreases the CPU load for this channel. Sounds most affected by the absence of linear interpolation are sinusoidal sounds. Sounds least affected are noisy sound effects like explosions and screams.
  3421. initNoDrop    Do not use drop-sample conversion to fake sample rate conversion. Using the initNoDrop initialization parameter increases the CPU load for the channel but results in a smoother sound.
  3422. The Sound Manager also recognizes the following masks, which you can use to select various channel attributes:
  3423. CONST
  3424.     initPanMask                        = $0003;                {mask for right/left pan values}
  3425.     initSRateMask                        = $0030;                {mask for sample rate values}
  3426.     initStereoMask                        = $00C0;                {mask for mono/stereo values}
  3427.     initCompMask                        = $FF00;                {mask for compression IDs}
  3428. Sound Command Numbers
  3429.  
  3430. You can perform many sound-related operations by sending sound commands to a sound channel. For example, to change the volume of a sound that is currently playing, you can send the ampCmd sound command to the channel using the SndDoImmediate routine. Similarly, to change the volume of all sounds subsequently to be played in a sound channel, you can send the volumeCmd sound command to that channel using the SndDoCommand routine.
  3431. The cmd field of the SndCommand data structure (described on page 2-99) specifies the sound command you want to execute. The param1 and param2 fields of that structure contain any additional information that might be needed to complete the command. One or both of these parameter fields might be ignored by a particular sound command. In some cases, the Sound Manager returns information to your application in one of the parameter fields.
  3432. IMPORTANT
  3433. In general, you’ll use either SndDoCommand or SndDoImmediate to send sound commands to a sound channel. With several commands, however, you must use the SndControl function to issue the sound command. In Sound Manager version 3.0 and later, however, you virtually never need to use SndControl because the commands that require it are either no longer supported (for example, availableCmd, totalLoadCmd, and loadCmd) or are obsolete (for example, versionCmd). The sound commands specific to the SndControl function are documented here for completeness only.s
  3434. The sound commands available to your application are defined by constants.
  3435. CONST
  3436.     nullCmd                        = 0;                {do nothing}
  3437.     quietCmd                        = 3;                {stop a sound that is playing}
  3438.     flushCmd                        = 4;                {flush a sound channel}
  3439.     reInitCmd                        = 5;                {reinitialize a sound channel}
  3440.     waitCmd                        = 10;                {suspend processing in a channel}
  3441.     pauseCmd                        = 11;                {pause processing in a channel}
  3442.     resumeCmd                        = 12;                {resume processing in a channel}
  3443.     callBackCmd                        = 13;                {execute a callback procedure}
  3444.     syncCmd                        = 14;                {synchronize channels}
  3445.     availableCmd                        = 24;                {see if initialization options are }
  3446.                                             { supported}
  3447.     versionCmd                        = 25;                {determine version}
  3448.     totalLoadCmd                        = 26;                {report total CPU load}
  3449.     loadCmd                        = 27;                {report CPU load for a new channel}
  3450.     freqDurationCmd                        = 40;                {play a note for a duration}
  3451.     restCmd                        = 41;                {rest a channel for a duration}
  3452.     freqCmd                        = 42;                {change the pitch of a sound
  3453.     ampCmd                        = 43;                {change the amplitude of a sound}
  3454.     timbreCmd                        = 44;                {change the timbre of a sound}
  3455.     getAmpCmd                        = 45;                {get the amplitude of a sound}
  3456.     volumeCmd                        = 46;                {set volume}
  3457.     getVolumeCmd                        = 47;                {get volume}
  3458.     waveTableCmd                        = 60;                {install a wave table as a voice}
  3459.     soundCmd                        = 80;                {install a sampled sound as a voice}
  3460.     bufferCmd                        = 81;                {play a sampled sound}
  3461.     rateCmd                        = 82;                {set the pitch of a sampled sound}
  3462.     getRateCmd                        = 85;                {get the pitch of a sampled sound}
  3463. Constant descriptions
  3464. nullCmd    Do nothing.
  3465. param1: 0 (ignored on input and output)
  3466. param2: 0 (ignored on input and output)
  3467. quietCmd    Stop the sound that is currently playing. You should send quietCmd by using SndDoImmediate.
  3468. param1: 0 (ignored on input and output)
  3469. param2: 0 (ignored on input and output)
  3470. flushCmd    Remove all commands currently queued in the specified sound channel. A flushCmd command does not affect any sound that is currently in progress. You should send flushCmd by using SndDoImmediate.
  3471. param1: 0 (ignored on input and output)
  3472. param2: 0 (ignored on input and output)
  3473. reInitCmd    Reset the initialization parameters specified in param2 for the specified channel.
  3474. param1: 0 (ignored on input and output)
  3475. param2: initialization parameters
  3476. waitCmd    Suspend further command processing in a channel until the specified duration has elapsed. To achieve sounds longer than 32,767 half-milliseconds, Pascal programmers can pass a negative number in param1, in which case the sound plays for 32,767 half-milliseconds plus the absolute value of param1.
  3477. param1: duration in half-milliseconds (0 to 65,565)
  3478. param2: 0 (ignored on input and output)
  3479. pauseCmd    Pause any further command processing in a channel until resumeCmd is received.
  3480. param1: 0 (ignored on input and output)
  3481. param2: 0 (ignored on input and output)
  3482. resumeCmd    Resume command processing in a channel that was previously paused by pauseCmd.
  3483. param1: 0 (ignored on input and output)
  3484. param2: 0 (ignored on input and output)
  3485. callBackCmd    Execute the callback procedure specified as a parameter to the SndNewChannel function. Both param1 and param2 are application-specific; you can use these two parameters to send data to your callback routine.
  3486. param1: application-defined
  3487. param2: application-defined
  3488. syncCmd    Synchronize multiple channels of sound. A syncCmd command is held in the specified channel, suspending all further command processing. The param2 parameter contains an identifier that is arbitrary. Each time the Sound Manager receives syncCmd, it decrements the count parameter for each channel having that identifier. When the count for a specific channel reaches 0, command processing in that channel resumes.
  3489. param1: count
  3490. param2: identifier
  3491. availableCmd    Return 1 in param1 if the Sound Manager supports the initialization options specified in param2 and 0 otherwise. However, the Sound Manager might support certain initialization parameters in general but not on a specific machine. You should send availableCmd using the SndControl function.
  3492. param1: 0 on input; result of command on output
  3493. param2: initialization parameters
  3494. versionCmd    Previously, this command determined which version of a sound data format is available. The result is returned in param2. The high word of the result indicates the major revision number, and the low word indicates the minor revision number. For example, version 2.0 of a data format would be returned as $00020000. However, this command is obsolete, and your application should not rely on it. You send versionCmd by using the SndControl function.
  3495. param1: 0 (ignored on input and output)
  3496. param2: 0 on input; version on output
  3497. totalLoadCmd    Previously, this command determined the total CPU load factor for all existing sound activity and for a new sound channel having the initialization parameters specified in param2. However, this command is obsolete, and your application should not rely on it. You send totalLoadCmd by using the SndControl function.
  3498. param1: 0 on input, load factor on output
  3499. param2: initialization parameters
  3500. loadCmd    Previously, this command determined the CPU load factor that would be incurred by a new channel of sound having the initialization parameters specified in param2. The load factor returned in param1 is the percentage of CPU processing power that the specified sound channel would require. However, this command is obsolete, and your application should not rely on it. You send loadCmd by using the SndControl function.
  3501. param1: 0 on input, load factor on output
  3502. param2: initialization parameters
  3503. freqDurationCmd
  3504. Play the note specified in param2 for the duration specified in param1. To achieve sounds longer than 32,767 half-milliseconds, Pascal programmers can pass a negative number in param1, in which case the sound plays for 32,767 half-milliseconds plus the absolute value of param1. The param2 parameter must contain a value in the range 0 to 127. If you want the note to stop playing after the duration specified in param1, you must send quietCmd after freqDurationCmd.
  3505. param1: duration in half-milliseconds (0 to 65,565)
  3506. param2: desired frequency
  3507. restCmd    Rest a channel for a specified duration. The duration is specified in half-milliseconds in param1. To achieve sounds longer than 32,767 half-milliseconds, Pascal programmers can pass a negative number in param1, in which case the sound plays for 32,767 half-milliseconds plus the absolute value of param1.
  3508. param1: duration in half-milliseconds (0 to 65,565)
  3509. param2: 0 (ignored on input and output)
  3510. freqCmd    Change the frequency (or pitch) of a sound. If no sound is currently playing, then freqCmd causes the Sound Manager to begin playing indefinitely at the frequency specified in param2. If, however, no instrument is installed in the channel and you attempt to play either wave-table or sampled-sound data, no sound is produced. The param2 parameter must contain a value in the range 0 to 127. The freqCmd command is identical to the freqDurationCmd command, except that no duration is specified to a freqCmd command.
  3511. param1: 0 (ignored on input and output)
  3512. param2: desired frequency
  3513. ampCmd    Change the amplitude (or loudness) of a sound. If no sound is currently playing, then ampCmd sets the amplitude of the next sound to be played. You specify the amplitude in param1; the amplitude should be an integer in the range 0 to 255.
  3514. param1: desired amplitude
  3515. param2: 0 (ignored on input and output)
  3516. timbreCmd    Change the timbre (or tone) of a sound currently being defined using square-wave data. A timbre value of 0 produces a clear tone; a timbre value of 254 produces a buzzing tone. You can use timbreCmd only for sounds defined using square-wave data.
  3517. param1: desired timbre (0 to 254)
  3518. param2: 0 (ignored on input and output)
  3519. getAmpCmd    Determine the current amplitude (or loudness) of a sound. The amplitude is returned in an integer variable whose address you pass in param2 and is in the range 0 to 255.
  3520. param1: 0 (ignored on input and output)
  3521. param2: pointer to amplitude variable
  3522. volumeCmd    Set the right and left volumes of the specified sound channel to the volumes specified in the high and low words of param2. The value $0100 represents full volume, and $0080 represents half volume. You can specify values larger than $0100 to overdrive the volume. For example, setting param2 to $02000200 sets the volume on both left and right speakers to twice full volume. Note, however, that volumeCmd is available only in Sound Manager versions 3.0 and later.
  3523. param1: 0 (ignored on input and output)
  3524. param2: high word is right volume, low word is left volume
  3525. getVolumeCmd    Get the current right and left volumes of the specified sound channel. The volumes are returned in the high and low words of the long integer pointed to by param2. The value $0100 represents full volume, and $0080 represents half volume. Note, however, that getVolumeCmd is available only in Sound Manager versions 3.0 and later.
  3526. param1: 0 (ignored on input and output)
  3527. param2: pointer to volume data
  3528. waveTableCmd    Install a wave table as a voice in the specified channel. The param1 parameter specifies the length of the wave table, and the param2 parameter is a pointer to the wave-table data itself. You can use waveTableCmd only for sounds defined using wave-table data.
  3529. param1: length of wave table
  3530. param2: pointer to wave-table data
  3531. soundCmd    Install a sampled sound as a voice in a channel. If the high bit of the command is set, param2 is interpreted as an offset from the beginning of the 'snd ' resource containing the command to the sound header. If the high bit is not set, param2 is interpreted as a pointer to the sound header. You can use the soundCmd command only with noncompressed sampled-sound data. You can also use soundCmd to preconfigure a sound channel, so that you can later send sound commands to it at interrupt time.
  3532. param1: 0 (ignored on input and output)
  3533. param2: offset or pointer to sound header
  3534. bufferCmd    Play a buffer of sampled-sound data. If the high bit of the command is set, param2 is interpreted as an offset from the beginning of the 'snd ' resource containing the command to the sound header. If the high bit is not set, param2 is interpreted as a pointer to the sound header. You can use bufferCmd only with sampled-sound data. Note that sending a bufferCmd resets the rate of the channel to 1.0.
  3535. param1: 0 (ignored on input and output)
  3536. param2: offset or pointer to sound header
  3537. rateCmd    Set the rate of a sampled sound that is currently playing, thus effectively altering its pitch and duration. Your application can set a rate of 0 to pause a sampled sound that is playing. The new rate is set to the value specified in param2, which is interpreted relative to 22 kHz. (For example, to set the rate to 44 kHz, pass $00020000 in param2; see Listing 2-4 on page 2-26 for sample code that uses rateCmd.) You can use rateCmd only with sampled-sound data.
  3538. param1: 0 (ignored on input and output)
  3539. param2: desired rate of sound
  3540. getRateCmd    Determine the sample rate of the sampled sound currently playing. The current rate of the channel is returned in a Fixed variable whose address you pass in param2 of the sound command. The values returned are always relative to the 22 kHz sampling rate, as with the rateCmd sound command. You can use getRateCmd only with sampled-sound data, and you should send it by using SndDoImmediate.
  3541. param1: 0 (ignored on input and output)
  3542. param2: pointer to rate variable
  3543. Chunk IDs
  3544.  
  3545. You can use the following constants to specify a chunk ID, a 4-byte value that identifies the type of a chunk in an AIFF or AIFF-C file.
  3546. CONST
  3547.     {IDs for AIFF and AIFF-C file chunks}
  3548.     FormID                                = 'FORM';                {ID for Form Chunk}
  3549.     FormatVersionID                                = 'FVER';                {ID for Format Version Chunk}
  3550.     CommonID                                = 'COMM';                {ID for Common Chunk}
  3551.     SoundDataID                                = 'SSND';                {ID for Sound Data Chunk}
  3552.     MarkerID                                = 'MARK';                {ID for Marker Chunk}
  3553.     InstrumentID                                = 'INST';                {ID for Instrument Chunk}
  3554.     MIDIDataID                                = 'MIDI';                {ID for MIDI Data Chunk}
  3555.     AudioRecordingID                                = 'AESD';                {ID for Recording Chunk}
  3556.      ApplicationSpecificID                                = 'APPL';                {ID for Application Chunk}
  3557.     CommentID                                = 'COMT';                {ID for Comment Chunk}
  3558.     NameID                                = 'NAME';                {ID for Name Chunk}
  3559.     AuthorID                                = 'AUTH';                {ID for Author Chunk}
  3560.     CopyrightID                                = '(c) ';                {ID for Copyright Chunk}
  3561.     AnnotationID                                = 'ANNO';                {ID for Annotation Chunk}
  3562. Constant descriptions
  3563. FormID    The Form Chunk. A Form Chunk contains information about the format of the file, and contains all the other chunks of the file.
  3564. FormatVersionID
  3565. The Format Version Chunk. A Format Version Chunk contains an indication of the version of the AIFF-C specification according to which this file is structured (AIFF-C only).
  3566. CommonID    The Common Chunk. A Common Chunk contains information about the sampled sound, such as the sampling rate and sample size.
  3567. SoundDataID    The Sound Data Chunk. A Sound Data Chunk contains the sample frames that comprise the sampled sound.
  3568. MarkerID    The Marker Chunk. A Marker Chunk contains markers that point to positions in the sound data.
  3569. InstrumentID    The Instrument Chunk. An Instrument Chunk defines basic parameters that an instrument (such as a sampling keyboard) can use to play back the sound data.
  3570. MIDIDataID    The MIDI Data Chunk. A MIDI Chunk contains MIDI data.
  3571. AudioRecordingID
  3572. The Audio Recording Chunk. An Audio Recording Chunk contains information pertaining to audio recording devices.
  3573. ApplicationSpecificID
  3574. The Application Chunk. An Application Chunk contains application-specific information.
  3575. CommentID    The Comment Chunk. A Comment Chunk contains a comment.
  3576. NameID    The Name Chunk. A Name Chunk contains the name of the sampled sound.
  3577. AuthorID    The Author Chunk. An Author Chunk contains one or more names of the authors (or creators) of the sampled sound.
  3578. CopyrightID    The Copyright Chunk. A Copyright Chunk contains a copyright notice for the sampled sound.
  3579. AnnotationID    The Annotation Chunk. An Annotation Chunk contains a comment.
  3580. Data Structures
  3581.  
  3582. This section describes the data structures that the Sound Manager defines. The Sound Manager uses many of these data structures (such as sound headers) to store information about sounds or sound channels. You should use these data structures only if you need to access this information or to customize sound play. The Sound Manager also defines several data structures that allow you to control sound output or to receive information about its status.
  3583. You use the sound command record to define a sound command that you send to the Sound Manager using either the SndDoCommand or SndDoImmediate functions.
  3584. If you want to play only a portion of a sound, you can use an audio selection record in conjunction with the SndStartFilePlay function.
  3585. You use the sound channel status record to obtain information from the Sound Manager about a specific sound channel, and you use the Sound Manager status record to obtain information about all sound channels.
  3586. The sound channel record stores information about a sound channel. Many of the fields of this record are for internal Sound Manager use only, but there are a few that you can access directly.
  3587. The sound header record stores information about sampled-sound data. You can use a sound header record to obtain information on a sound or to change a sound’s loop points. The extended sound header record and the compressed sound header record add several fields to the sound header record that provide more information about a sound.
  3588. If your application uses the SndPlayDoubleBuffer function to customize the double buffering of sound data, you need to set up a sound double buffer header record, which must include pointers to two sound double buffer records.
  3589. Sound Command Records
  3590.  
  3591. A sound command record describes a sound command that you send to a sound channel using the SndDoCommand or SndDoImmediate function. The SndCommand data type defines a sound command record.
  3592. TYPE SndCommand =
  3593. PACKED RECORD
  3594.     cmd:                Integer;                {command number}
  3595.     param1:                Integer;                {first parameter}
  3596.     param2:                 LongInt;                {second parameter}
  3597. END;
  3598. Field descriptions
  3599. cmd    The number of the sound command you wish to execute. 
  3600. param1    The first parameter of the sound command.
  3601. param2    The second parameter of the sound command.
  3602. The meaning of the param1 and param2 fields depends on the particular sound command being issued. See “Sound Command Numbers” beginning on page 2-92 for a description of the sound commands your application can use.
  3603. Audio Selection Records
  3604.  
  3605. You can pass a pointer to an audio selection record to the SndStartFilePlay function to play only part of a sound in a file on disk. The AudioSelection data type defines an audio selection record.
  3606. TYPE AudioSelection =
  3607. PACKED RECORD
  3608.     unitType:                LongInt;                {type of time unit}
  3609.     selStart:                Fixed;                {starting point of selection}
  3610.     selEnd:                Fixed;                {ending point of selection}
  3611. END;
  3612. Field descriptions
  3613. unitType    The type of unit of time used in the selStart and selEnd fields. You can set this to seconds by specifying the constant unitTypeSeconds.
  3614. selStart    The starting point in seconds of the sound to play. If selStart is greater than selEnd, SndStartFilePlay returns an error.
  3615. selEnd    The ending point in seconds of the sound to play.
  3616. Use a constant to specify the unit type.
  3617. CONST
  3618.     unitTypeSeconds                                = $0000;                {seconds}
  3619.     unitTypeNoSelection                                = $FFFF;                {no selection}
  3620. If the value in the unitType field is unitTypeNoSelection, then the values in the selStart and selEnd fields are ignored and the entire sound plays. Alternatively, if you wish to play an entire sound, you can pass NIL instead of a pointer to an audio selection record to the SndStartFilePlay function.
  3621. Sound Channel Status Records
  3622.  
  3623. To obtain information about a sound channel, you can pass a pointer to a sound channel status record to the SndChannelStatus function. The SCStatus data type defines a sound channel status record.
  3624. TYPE SCStatus =
  3625. RECORD
  3626.     scStartTime:                                Fixed;                {starting time for play from disk}
  3627.     scEndTime:                                Fixed;                {ending time for play from disk}
  3628.     scCurrentTime:                                Fixed;                {current time for play from disk}
  3629.     scChannelBusy:                                Boolean;                {TRUE if channel is processing cmds}
  3630.     scChannelDisposed:                                Boolean;                {reserved}
  3631.     scChannelPaused:                                Boolean;                {TRUE if channel is paused}
  3632.     scUnused:                                Boolean;                {unused}
  3633.     scChannelAttributes:                                LongInt;                {attributes of this channel}
  3634.     scCPULoad:                                LongInt;                {CPU load for this channel}
  3635. END;
  3636. Field descriptions
  3637. scStartTime    If the Sound Manager is playing from disk through the specified sound channel, then scStartTime is the starting time in seconds from the beginning of the sound for the play from disk. Otherwise, scStartTime is 0.
  3638. scEndTime    If the Sound Manager is playing from disk through the specified sound channel, then scEndTime is the ending time in seconds from the beginning of the sound for the play from disk. Otherwise, scEndTime is 0.
  3639. scCurrentTime    If the Sound Manager is playing from disk through the specified sound channel, then scCurrentTime is the current time in seconds from the beginning of the disk play. Otherwise, scCurrentTime is 0. The Sound Manager updates the value of this field only periodically, and you should not rely on the accuracy of its value.
  3640. scChannelBusy    If the specified channel is currently processing sound commands, then scChannelBusy is TRUE; otherwise, scChannelBusy is FALSE.
  3641. scChannelDisposed
  3642. Reserved for use by Apple Computer, Inc.
  3643. scChannelPaused
  3644. If the Sound Manager is playing from disk through the specified sound channel and the play from disk is paused, then scChannelPaused is TRUE; otherwise, scChannelPaused is FALSE. This field is also TRUE if the channel was paused with the pauseCmd sound command.
  3645. scUnused    Reserved for use by Apple Computer, Inc.
  3646. scChannelAttributes
  3647. The current attributes of the specified channel. These attributes are in the channel initialization parameters format. The value returned in this field is always identical to the value passed in the init parameter to SndNewChannel.
  3648. scCPULoad    The CPU load for the specified channel. You should not rely on the value in this field.
  3649. You can mask out certain values in the scChannelAttributes field to determine how a channel has been initialized.
  3650. CONST
  3651.     initPanMask                    = $0003;                {mask for right/left pan values}
  3652.     initSRateMask                    = $0030;                {mask for sample rate values}
  3653.     initStereoMask                    = $00C0;                {mask for mono/stereo values}
  3654.     initCompMask                    = $FF00;                {mask for compression IDs}
  3655. Sound Manager Status Records
  3656.  
  3657. You can use the SndManagerStatus function to get a Sound Manager status record, which gives information on the current CPU loading caused by all open channels of sound. The SMStatus data type defines a Sound Manager status record.
  3658. TYPE SMStatus =
  3659. PACKED RECORD
  3660.     smMaxCPULoad:                        Integer;                {maximum load on all channels}
  3661.     smNumChannels:                        Integer;                {number of allocated channels}
  3662.     smCurCPULoad:                        Integer;                {current load on all channels}
  3663. END;
  3664. Field descriptions
  3665. smMaxCPULoad    The maximum CPU load that the Sound Manager will not exceed when allocating channels. The smMaxCPULoad field is set to a default value of 100 when the system starts up.
  3666. smNumChannels    The number of sound channels that are currently allocated by all applications. This does not mean that the channels allocated are being used, only that they have been allocated and that CPU loading is being reserved for these channels.
  3667. smCurCPULoad    The CPU load that is being taken up by currently allocated channels.
  3668. IMPORTANT
  3669. Although you can use the information contained in the Sound Manager status record to determine how many channels are allocated, you should not rely on the information in the smMaxCPULoad or smCurCPULoad field. To determine whether the Sound Manager can create a new channel, simply call the SndNewChannel function, which returns an appropriate result code if it is unable to allocate a new channel.s
  3670. Sound Channel Records
  3671.  
  3672. The Sound Manager maintains a sound channel record to store information about each sound channel that you allocate directly by calling the SndNewChannel function or indirectly by passing a NIL channel to a high-level Sound Manager routine like the SndPlay function. The SndChannel data type defines a sound channel record.
  3673. TYPE SndChannel =
  3674. PACKED RECORD
  3675.     nextChan:                    SndChannelPtr;                    {pointer to next channel}
  3676.     firstMod:                    Ptr;                    {used internally}
  3677.     callBack:                    ProcPtr;                    {pointer to callback procedure}
  3678.     userInfo:                    LongInt;                    {free for application's use}
  3679.     wait:                    LongInt;                    {used internally}
  3680.     cmdInProgress:                    SndCommand;                    {used internally}
  3681.     flags:                    Integer;                    {used internally}
  3682.     qLength:                    Integer;                    {used internally}
  3683.     qHead:                    Integer;                    {used internally}
  3684.     qTail:                    Integer;                    {used internally}
  3685.     queue:                    ARRAY[0..stdQLength-1] OF SndCommand;
  3686. END; 
  3687. Field descriptions
  3688. nextChan    A pointer to the next sound channel in a single queue of channels that the Sound Manager maintains for all applications.
  3689. firstMod    Used internally.
  3690. callBack    A pointer to the callback procedure associated with the sound channel. See page 2-152 for information on this callback procedure.
  3691. userInfo    A value that your application can use to store information.
  3692. wait    Used internally.
  3693. cmdInProgress    Used internally.
  3694. flags    Used internally.
  3695. qLength    Used internally.
  3696. qHead    Used internally.
  3697. qTail    Used internally.
  3698. queue    The sound commands pending for the sound channel.
  3699. The only field of the sound channel record that you are likely to need to access directly is the userInfo field. This field is useful if you need to pass a value to a Sound Manager callback procedure or completion routine. For example, you might pass the value stored in the A5 register so that your callback procedure can access your application’s global variables. Or, you might store a handle to sound data here so that a routine that disposes of an allocated channel can also release the sound data that the channel played.
  3700. In rarer instances, you might need to access the callBack field of the sound channel record directly. Ordinarily, you set this field by specifying a callback procedure when you call the SndNewChannel function. However, you can change the callback procedure associated with a channel by changing this field directly. The Sound Manager will then execute the procedure you specify in this field whenever the channel processes a callBackCmd command.
  3701. sWARNING
  3702. You should not attempt to manipulate all open sound channels by using the nextChan field to walk the sound channel queue. The queue might contain channels opened by other applications. If you need to perform some operation on all sound channels that your application has allocated, you should maintain your own data structure that keeps track of your application’s channels.s
  3703. Sound Header Records
  3704.  
  3705. Sound resources often contain sampled-sound data as well as sound commands. The sound data is contained in the last field of the sound header. You can access a sound header record to find information about sampled-sound data. The standard sound header is used only for simple monophonic sounds. The SoundHeader data type defines a sampled sound header record.
  3706. TYPE SoundHeader =
  3707. PACKED RECORD
  3708.     samplePtr:                    Ptr;                {if NIL, samples in sampleArea}
  3709.     length:                    LongInt;                {number of samples in array}
  3710.     sampleRate:                    Fixed;                {sample rate}
  3711.     loopStart:                    LongInt;                {loop point beginning}
  3712.     loopEnd:                    LongInt;                {loop point ending}
  3713.     encode:                    Byte;                {sample's encoding option}
  3714.     baseFrequency:                    Byte;                {base frequency of sample}
  3715.     sampleArea:                    PACKED ARRAY[0..0] OF Byte;
  3716. END;
  3717. Field descriptions
  3718. samplePtr    A pointer to the sampled-sound data. If the sampled sound is located in memory immediately after the baseFrequency field, then this field should be set to NIL. Otherwise, this field is a pointer to the memory location of the sampled-sound data. (This might be useful if you want to change some fields of a sound header but do not want to modify a handle to a sound resource directly.)
  3719. length    The number of bytes of sound data.
  3720. sampleRate    The rate at which the sample was originally recorded. The Sound Manager can play sounds sampled at any rate up to 64 kHz. The values corresponding to the three most common sample rates (11 kHz, 22 kHz, and 44 kHz) are defined by constants:
  3721.                     CONST
  3722.                         rate44khz                = $AC440000;                    {44100.00000 Fixed}
  3723.                         rate22khz                = $56EE8BA3;                    {22254.54545 Fixed}
  3724.                         rate11khz                = $2B7745D1;                    {11127.27273 Fixed}
  3725.     Note that the sample rate is declared as a Fixed data type, but the most significant bit is not treated as a sign bit; instead, that bit is interpreted as having the value 32,768.
  3726. loopStart    The starting point of the portion of the sampled sound header that is to be used by the Sound Manager when determining the duration of freqDurationCmd. These loop points specify the byte numbers in the sampled data to be used as the beginning and end points to cycle through when playing the sound. The loop starting and ending points are 0-based.
  3727. loopEnd    The end point of the portion of the sampled sound header that is to be used by the Sound Manager when determining the duration of freqDurationCmd. If no looping is desired, set both loopStart and loopEnd to 0.
  3728. encode    The method of encoding used to generate the sampled-sound data. The current encoding option values are
  3729.                     CONST
  3730.                         stdSH            = $00;            {standard sound header}
  3731.                         extSH            = $FF;            {extended sound header}
  3732.                         cmpSH            = $FE;            {compressed sound header}
  3733.     For a standard sound header, you should specify the constant stdSH. Encode option values in the ranges 0 through 63 and 128 to 255 are reserved for use by Apple. You are free to use numbers in the range 64 through 127 for your own encode options.
  3734. baseFrequency    The pitch at which the original sample was taken. This value must be in the range 1 through 127. Table 2-2 on page 2-43 lists the possible baseFrequency values. The baseFrequency value allows the Sound Manager to calculate the proper playback rate of the sample when an application uses the freqDurationCmd command. Applications should not alter the baseFrequency field of a sampled sound; to play the sample at different pitches, use freqDurationCmd or freqCmd.
  3735. sampleArea    If the value of samplePtr is NIL, this field is an array of bytes, each of which contains a value similar to the values in a wave-table description. These values are interpreted as offset values, where $80 represents an amplitude of 0. The value $00 is the most negative amplitude, and $FF is the largest positive amplitude. The samples are numbered 1 through the value in the length parameter.
  3736. If you need to create a sound header for sampled-sound data that your application has recorded, then you should use the SetupSndHeader function, described in the chapter “Sound Input Manager” in this book.
  3737. Extended Sound Header Records
  3738.  
  3739. For sampled-sound data that is more complex than a standard sound header can describe, the Sound Manager uses an extended sound header record. Sound data described by such a header can be monophonic or stereo, but it cannot be compressed.
  3740. Most of the fields of the extended sound header correspond to fields of the sampled sound header. However, the extended sound header allows the encoding of stereo sound. The numChannels field contains the number of channels of sound recorded, and the numFrames field contains the number of frames of sound recorded in each channel. For more information on the format of sampled sound frames, see “Sound Files” on page 2-81.
  3741. Note
  3742. The word “channel” can be confusing in this context, because a sound resource containing polyphonic sound (that is, multichannel sound) can be played on a single Sound Manager sound channel. Channel is a general term for the portion of sound data that can be described by a single sound wave. Monophonic sound is composed of a single channel. Stereo sound (also called polyphonic sound) is composed of several channels of sound played simultaneously. “Sound channel” is a term specific to the Sound Manager.u
  3743. TYPE ExtSoundHeader =
  3744. PACKED RECORD
  3745.     samplePtr:                        Ptr;                {if NIL, samples in sampleArea}
  3746.     numChannels:                        LongInt;                {number of channels in sample}
  3747.     sampleRate:                        Fixed;                {rate of original sample}
  3748.     loopStart:                        LongInt;                {loop point beginning}
  3749.     loopEnd:                        LongInt;                {loop point ending}
  3750.     encode:                        Byte;                {sample's encoding option}
  3751.     baseFrequency:                        Byte;                {base freq. of original sample}
  3752.     numFrames:                        LongInt;                {total number of frames}
  3753.     AIFFSampleRate:                        Extended80;                {rate of original sample}
  3754.     markerChunk:                        Ptr;                {reserved}
  3755.     instrumentChunks:                        Ptr;                {pointer to instrument info}
  3756.     AESRecording:                        Ptr;                {pointer to audio info}
  3757.     sampleSize:                        Integer;                {number of bits per sample}
  3758.     futureUse1:                        Integer;                {reserved}
  3759.     futureUse2:                        LongInt;                {reserved}
  3760.     futureUse3:                        LongInt;                {reserved}
  3761.     futureUse4:                        LongInt;                {reserved}
  3762.     sampleArea:                        PACKED ARRAY[0..0] OF Byte;
  3763. END;
  3764. Field descriptions
  3765. Field descriptions
  3766. samplePtr    A pointer to the sampled-sound data. If the sampled sound is located in memory immediately after the futureUse4 field, then this field should be set to NIL. Otherwise, this field is a pointer to the memory location of the sampled-sound data.
  3767. numChannels    The number of channels in the sampled-sound data.
  3768. sampleRate    The rate at which the sample was originally recorded. The approximate sample rates are shown in Table 2-1 on page 2-16. Note that the sample rate is declared as a Fixed data type, but the most significant bit is not treated as a sign bit; instead, that bit is interpreted as having the value 32,768.
  3769. loopStart    The starting point of the portion of the extended sampled sound header that is to be used by the Sound Manager when determining the duration of freqDurationCmd. These loop points specify the byte numbers in the sampled data to be used as the beginning and end points to cycle through when playing the sound. The loop starting and ending points are 0-based.
  3770. loopEnd    The end point of the portion of the extended sampled sound header that is to be used by the Sound Manager when determining the duration of freqDurationCmd.
  3771. encode    The method of encoding used to generate the sampled-sound data. For an extended sound header, you should specify the constant extSH. Encode option values in the ranges 0 through 63 and 128 to 255 are reserved for use by Apple. You are free to use numbers in the range 64 through 127 for your own encode options.
  3772. baseFrequency    The pitch at which the original sample was taken. This value must be in the range 1 through 127. Table 2-2 on page 2-43 lists the possible baseFrequency values. The baseFrequency value allows the Sound Manager to calculate the proper playback rate of the sample when an application uses the freqDurationCmd command. Applications should not alter the baseFrequency field of a sampled sound; to play the sample at different pitches, use freqDurationCmd or freqCmd.
  3773. numFrames    The number of frames in the sampled-sound data. Each frame contains numChannels bytes for 8-bit sound data.
  3774. AIFFSampleRate    The sample rate at which the frames were sampled before compression, as expressed in the 80-bit extended data type representation.
  3775. markerChunk    Synchronization information. The markerChunk field is not presently used and should be set to NIL.
  3776. instrumentChunks
  3777. Instrument information.
  3778. AESRecording    Information related to audio recording devices.
  3779. sampleSize    The number of bits in each sample frame.
  3780. futureUse1    Reserved.
  3781. futureUse2    Reserved.
  3782. futureUse3    Reserved.
  3783. futureUse4    The four futureUse fields are reserved for use by Apple. To maintain compatibility with future releases of system software, you should always set these fields to 0.
  3784. sampleArea    An array of interleaved sample points, each of which contains a value similar to the values in a wave-table description. For 8-bit sampled-sound data, these values are interpreted as offset values, where $80 represents an amplitude of 0. The value $00 is the largest negative amplitude, and $FF is the largest positive amplitude.
  3785. To compute the total number of bytes of a sample, multiply the values in the numChannels, numFrames, and sampleSize fields and divide by the number of bytes per sample (typically 8 or 16).
  3786. Note
  3787. Although extended sound headers (and compressed sound headers, described next) support the storage of 16-bit sound, only versions 3.0 and later of the Sound Manager can play 16-bit sounds. If your application uses 16-bit sound, you must convert it to 8-bit sound before earlier versions of the Sound Manager can play it.u
  3788. Compressed Sound Header Records
  3789.  
  3790. To describe compressed sampled-sound data, the Sound Manager uses a compressed sound header record. Compressed sound headers include all of the essential fields of extended sound headers in addition to several fields that pertain to compression. The CmpSoundHeader data type defines the compressed sound header record.
  3791. TYPE CmpSoundHeader =
  3792. PACKED RECORD
  3793.     samplePtr:                        Ptr;                    {if NIL, samples in sampleArea}
  3794.     numChannels:                        LongInt;                    {number of channels in sample}
  3795.     sampleRate:                        Fixed;                    {rate of original sample}
  3796.     loopStart:                        LongInt;                    {loop point beginning}
  3797.     loopEnd:                        LongInt;                    {loop point ending}
  3798.     encode:                        Byte;                    {sample's encoding option}
  3799.     baseFrequency:                        Byte;                    {base freq. of original sample}
  3800.     numFrames:                        LongInt;                    {length of sample in frames}
  3801.     AIFFSampleRate:                        Extended80;                    {rate of original sample}
  3802.     markerChunk:                        Ptr;                    {reserved}
  3803.     format:                        OSType;                    {data format type}
  3804.     futureUse2:                        LongInt;                    {reserved}
  3805.     stateVars:                        StateBlockPtr;                    {pointer to StateBlock}
  3806.     leftOverSamples:                        LeftOverBlockPtr;
  3807.                                                 {pointer to LeftOverBlock}
  3808.     compressionID:                        Integer;                    {ID of compression algorithm}
  3809.     packetSize:                        Integer;                    {number of bits per packet}
  3810.     snthID:                        Integer;                    {unused}
  3811.     sampleSize:                        Integer;                    {bits in each sample point}
  3812.     sampleArea:                        PACKED ARRAY[0..0] OF Byte;
  3813. END;
  3814. Field descriptions
  3815. samplePtr    The location of the compressed sound frames. If samplePtr is NIL, then the frames are located in the sampleArea field of the compressed sound header. Otherwise, samplePtr points to a buffer that contains the frames.
  3816. numChannels    The number of channels in the sample.
  3817. sampleRate    The sample rate at which the frames were sampled before compression. The approximate sample rates are shown in Table 2-1 on page 2-16. Note that the sample rate is declared as a Fixed data type, but the most significant bit is not treated as a sign bit; instead, that bit is interpreted as having the value 32,768.
  3818. loopStart    The beginning of the loop points of the sound before compression. The loop starting and ending points are 0-based.
  3819. loopEnd    The end of the loop points of the sound before compression.
  3820. encode    The method of encoding (if any) used to generate the sampled-sound data. For a compressed sound header, you should specify the constant cmpSH. Encode option values in the ranges 0 through 63 and 128 to 255 are reserved for use by Apple. You are free to use numbers in the range 64 through 127 for your own encode options.
  3821. baseFrequency    The pitch of the original sampled sound. It is not used by bufferCmd. If you wish to make use of baseFrequency with a compressed sound, you must first expand it and then play it with soundCmd and freqDurationCmd.
  3822. numFrames    The number of frames contained in the compressed sound header. When you store multiple channels of noncompressed sound, store them as interleaved sample frames (as in AIFF). When you store multiple channels of compressed sounds, store them as interleaved packet frames.
  3823. AIFFSampleRate
  3824. The sample rate at which the frames were sampled before compression, as expressed in the 80-bit extended data type representation.
  3825. markerChunk    Synchronization information. The markerChunk field is not presently used and should be set to NIL.
  3826. format    The data format type. This field contains a value of type OSType that defines the compression algorithm, if any, used to generate the audio data. For example, for data generated using MACE 3:1 compression, this field should contain the value 'MAC3'. See page 2-86 for a list of the format types defined by Apple. This field is used only if the compressionID field contains the value fixedCompression.
  3827. futureUse2    This field is reserved for use by Apple. To maintain compatibility with future releases of system software, you should always set this field to 0.
  3828. stateVars    A pointer to a state block. This field is used to store the state variables for a given algorithm across consecutive calls. See “State Blocks” on page 2-119 for a description of the state block.
  3829. leftOverSamples
  3830. A pointer to a leftover block. You can use this block to store samples that will be truncated across algorithm invocations. See “Leftover Blocks” on page 2-119 for a description of the leftover block.
  3831. compressionID    The compression algorithm used on the samples in the compressed sound header. You can use a constant to define the compression algorithm.
  3832.                     CONST
  3833.                         variableCompression                            
  3834.                                                 = -2;        {variable-ratio compr.}
  3835.                         fixedCompression                        = -1;        {fixed-ratio compr.}
  3836.                         notCompressed                        = 0;        {noncompressed samples}
  3837.                         threeToOne                        = 3;        {3:1 compressed samples}
  3838.                         sixToOne                        = 4;        {6:1 compressed samples}
  3839.     The constant fixedCompression is available only with Sound Manager versions 3.0 and later. If the compressionID field contains the value fixedCompression, the Sound Manager reads the format field to determine the compression algorithm used to generate the compressed data. Otherwise, the Sound Manager reads the compressionID field. Apple reserves the right to use compression IDs in the range 0 through 511. Currently the constant variableCompression is not used by the Sound Manager.
  3840. packetSize    The size, in bits, of the smallest element that a given expansion algorithm can work with. You can use a constant to define the packet size.
  3841.                     CONST
  3842.                         sixToOnePacketSize                            = 8;        {size for 6:1}
  3843.                         threeToOnePacketSize                            = 16;        {size for 3:1}
  3844.     Beginning with Sound Manager version 3.0, you can specify the value 0 in this field to instruct the Sound Manager to determine the packet size itself.
  3845. snthID    This field is unused. You should set it to 0.
  3846. sampleSize    The size of the sample before it was compressed. The samples passed in the compressed sound header should always be byte-aligned, and any padding done to achieve byte alignment should be done from the left with zeros.
  3847. sampleArea    The sample frames, but only when the samplePtr field is NIL. Otherwise, the sample frames are in the location indicated by samplePtr.
  3848. Sound Double Buffer Header Records
  3849.  
  3850. You must fill in a sound double buffer header record and two sound double buffer records if you wish to manage your own double buffers. The SndDoubleBufferHeader data type defines a sound double buffer header.
  3851. TYPE SndDoubleBufferHeader =
  3852. PACKED RECORD
  3853.     dbhNumChannels:                            Integer;                    {number of sound channels}
  3854.     dbhSampleSize:                            Integer;                    {sample size, if noncompressed}
  3855.     dbhCompressionID:                            Integer;                    {ID of compression algorithm}
  3856.     dbhPacketSize:                            Integer;                    {number of bits per packet}
  3857.     dbhSampleRate:                            Fixed;                    {sample rate}
  3858.     dbhBufferPtr:                            ARRAY[0..1] OF SndDoubleBufferPtr;
  3859.                                                     {pointers to SndDoubleBuffer}
  3860.     dbhDoubleBack:                            ProcPtr;                    {pointer to doubleback procedure}
  3861. END;
  3862. Sound Manager versions 3.0 and later support custom compression and decompression algorithms by defining the revised sound double buffer header record, of type SndDoubleBufferHeader2. It’s identical to the SndDoubleBufferHeader data type except that it contains the dbhFormat field at the end.
  3863. TYPE SndDoubleBufferHeader2 =
  3864. PACKED RECORD
  3865.     dbhNumChannels:                            Integer;                    {number of sound channels}
  3866.     dbhSampleSize:                            Integer;                    {sample size, if noncompressed}
  3867.     dbhCompressionID:                            Integer;                    {ID of compression algorithm}
  3868.     dbhPacketSize:                            Integer;                    {number of bits per packet}
  3869.     dbhSampleRate:                            Fixed;                    {sample rate}
  3870.     dbhBufferPtr:                            ARRAY[0..1] OF SndDoubleBufferPtr;
  3871.                                                     {pointers to SndDoubleBuffer}
  3872.     dbhDoubleBack:                            ProcPtr;                    {pointer to doubleback procedure}
  3873.     dbhFormat:                            OSType;                    {signature of codec}
  3874. END;
  3875. Field descriptions
  3876. dbhNumChannels
  3877. The number of channels for the sound (1 for monophonic sound, 2 for stereo).
  3878. dbhSampleSize    The sample size for the sound if the sound is not compressed. If the sound is compressed, dbhSampleSize should be set to 0. Samples that are 1–8 bits have a dbhSampleSize value of 8; samples that are 9–16 bits have a dbhSampleSize value of 16. Currently, only 8-bit samples are supported. For further information on sample sizes, refer to the AIFF specification.
  3879. dbhCompressionID
  3880. The compression identification number of the compression algorithm, if the sound is compressed. If the sound is not compressed, dbhCompressionID should be set to 0.
  3881. dbhPacketSize    The packet size in bits for the compression algorithm specified by dbhCompressionID, if the sound is compressed.
  3882. dbhSampleRate    The sample rate for the sound. Note that the sample rate is declared as a Fixed data type, but the most significant bit is not treated as a sign bit; instead, that bit is interpreted as having the value 32,768.
  3883. dbhBufferPtr    An array of two pointers, each of which should point to a valid SndDoubleBuffer record.
  3884. dbhDoubleBack    A pointer to the application-defined routine that is called when the double buffers are switched and the exhausted buffer needs to be refilled.
  3885. dbhFormat    The data format type. This field contains a value of type OSType that defines the compression algorithm, if any, to be used to decompress the audio data. For example, for data generated using MACE 3:1 compression, this field should contain the value 'MAC3'. See page 2-86 for a list of the format types defined by Apple. This field is used only if the dbhCompressionID field contains the value fixedCompression.
  3886. The dbhBufferPtr array contains pointers to two sound double buffer records, whose format is defined below. These are the two buffers between which the Sound Manager switches until all the sound data has been sent into the sound channel. When you make the call to SndPlayDoubleBuffer, the two buffers should both already contain a nonzero number of frames of data.
  3887. Sound Double Buffer Records
  3888.  
  3889. You must fill in a sound double buffer header record if you wish to manage your own double buffers. The dbhBufferPtr field of the sound double buffer header record references two sound double buffer records, which you must also fill out. The SndDoubleBufferHeader data type defines a sound double buffer header.
  3890. TYPE SndDoubleBuffer =
  3891. PACKED RECORD
  3892.     dbNumFrames:                    LongInt;                                        {number of frames in buffer}
  3893.     dbFlags:                    LongInt;                                        {buffer status flags}
  3894.     dbUserInfo:                    ARRAY[0..1] OF LongInt;                                        {for application's use}
  3895.     dbSoundData:                    PACKED ARRAY[0..0] OF Byte;                                        {array of data}
  3896. END;
  3897. Field descriptions
  3898. Field descriptions
  3899. dbNumFrames    The number of frames in the dbSoundData array.
  3900. dbFlags    Buffer status flags.
  3901. dbUserInfo    Two long words into which you can place information that you need to access in your doubleback procedure.
  3902. dbSoundData    A variable-length array. You write samples into this array, and the Sound Manager reads samples out of this array.
  3903. The buffer status flags field for each of the two buffers can contain either of these values that your doubleback procedure must set when appropriate:
  3904. CONST
  3905.     dbBufferReady                        = $00000001;
  3906.     dbLastBuffer                        = $00000004;
  3907. All other bits in the dbFlags field are reserved by Apple; your application should not modify them.
  3908. Chunk Headers
  3909.  
  3910. Every chunk in an AIFF or AIFF-C file contains a chunk header that defines characteristics of the chunk. The ChunkHeader data type defines a chunk header.
  3911. TYPE ChunkHeader =
  3912. RECORD
  3913.     ckID:            ID;                {chunk type ID}
  3914.     ckSize:            LongInt;                {number of bytes of data}
  3915. END;
  3916. Field descriptions
  3917. ckID    The ID of the chunk. An ID is a 32-bit concatenation of any four printable ASCII characters in the range ' ' (space character, ASCII value $20) through '~' (ASCII value $7E). Spaces cannot precede printing characters, but trailing spaces are allowed. Control characters are not allowed. See “Chunk IDs” on page 2-98 for a list of the currently recognized chunk IDs.
  3918. ckSize    The size of the chunk in bytes, not including the ckID and ckSize fields.
  3919. Form Chunks
  3920.  
  3921. All sound files begin with a Form Chunk. This chunk defines the type and size of the file and can be thought of as enclosing the remaining chunks in the sound file. The ContainerChunk data type defines a Form Chunk.
  3922. TYPE ContainerChunk =
  3923. RECORD
  3924.     ckID:                ID;                {'FORM'}
  3925.     ckSize:                LongInt;                {number of bytes of data}
  3926.     formType:                ID;                {type of file}
  3927. END;
  3928. Field descriptions
  3929. ckID    The ID of this chunk. For a Form Chunk, this ID is 'FORM'.
  3930. ckSize    The size of the data portion of this chunk. Note that the data portion of a Form Chunk is divided into two parts, formType and the remaining chunks of the sound file.
  3931. formType    The type of audio file. For AIFF files, formType is 'AIFF'. For AIFF-C files, formType is 'AIFC'.
  3932. The size of an entire sound file is ckSize+8, because the ckSize field incorporates the size of all chunks of the sound file, except the sizes of the ckID and ckSize fields of the Form Chunk itself. 
  3933. Format Version Chunks
  3934.  
  3935. AIFF-C files each contain exactly one Format Version Chunk, but files of type AIFF do not contain any. You can examine the Format Version Chunk to ensure that your application can process an AIFF-C file. The FormatVersionChunk data type defines a Format Version Chunk.
  3936. TYPE FormatVersionChunk =
  3937. RECORD
  3938.     ckID:                ID;                {'FVER'}
  3939.     ckSize:                LongInt;                {4}
  3940.     timestamp:                LongInt;                {date of format version}
  3941. END;
  3942. Field descriptions
  3943. ckID    The ID of this chunk. For a Format Version Chunk, this ID is 'FVER'.
  3944. ckSize    The size of the data portion of this chunk. This value is always 4 in a Format Version Chunk because the timestamp field is 4 bytes long (the 8 bytes used by the ckID and ckSize fields are not included).
  3945. timestamp    An indication of when the format version for this kind of file was created. The value indicates the number of seconds between midnight, January 1, 1904, and the time at which the AIFF-C file format was created.
  3946. Common Chunks
  3947.  
  3948. Every AIFF and AIFF-C file contains a Common Chunk that defines some fundamental characteristics of the sampled sound contained in the file. The format of the Common Chunk is different for AIFF and AIFF-C files. As a result, you need to determine the type of file format (by inspecting the formType field of the Form Chunk) before reading the Common Chunk.
  3949. For AIFF files, the CommonChunk data type defines a Common Chunk.
  3950. TYPE CommonChunk =
  3951. RECORD
  3952.     ckID:                        ID;                {'COMM'}
  3953.     ckSize:                        LongInt;                {size of chunk data}
  3954.     numChannels:                        Integer;                {number of channels}
  3955.     numSampleFrames:                        LongInt;                {number of sample frames}
  3956.     sampleSize:                        Integer;                {number of bits per sample}
  3957.     sampleRate:                        Extended;                {number of frames per second}
  3958. END;
  3959. Field descriptions
  3960. ckID    The ID of this chunk. For a Common Chunk, this ID is 'COMM'.
  3961. ckSize    The size of the data portion of this chunk. In AIFF files, this field is always 18 because the 8 bytes used by the ckID and ckSize fields are not included. 
  3962. numChannels    The number of audio channels contained in the sampled sound. A value of 1 indicates monophonic sound, a value of 2 indicates stereo sound, a value of 4 indicates four-channel sound, and so forth. 
  3963. numSampleFrames
  3964. The number of sample frames in the Sound Data Chunk. Note that this field contains the number of sample frames, not the number of bytes of data and not the number of sample points. For noncompressed sound data, the total number of sample points in the file is numChannels * numSampleFrames. 
  3965. sampleSize    The number of bits in each sample point of noncompressed sound data. The sampleSize field can contain any integer from 1 to 32. For compressed sound data, this field indicates the number of bits per sample in the original sound data, before compression.
  3966. sampleRate    The sample rate at which the sound is to be played back, in sample frames per second.
  3967. Extended Common Chunks
  3968.  
  3969. An AIFF-C file contains an extended Common Chunk that includes all of the fields of the Common Chunk, but adds two fields that describe the type of compression (if any) used on the audio data. The ExtCommonChunk data type defines an extended Common Chunk.
  3970. TYPE ExtCommonChunk =
  3971. RECORD
  3972.     ckID:                        ID;                {'COMM'}
  3973.     ckSize:                        LongInt;                {size of chunk data}
  3974.     numChannels:                        Integer;                {number of channels}
  3975.     numSampleFrames:                        LongInt;                {number of sample frames}
  3976.     sampleSize:                        Integer;                {number of bits per sample}
  3977.     sampleRate:                        Extended;                {number of frames per second}
  3978.     compressionType:                        ID;                {compression type ID}
  3979.     compressionName:                        PACKED ARRAY[0..0] OF Byte;
  3980.                                             {compression type name}
  3981. END;
  3982. Field descriptions
  3983. ckID    The ID of this chunk. For an extended Common Chunk, this ID is 'COMM'.
  3984. ckSize    The size of the data portion of this chunk. For an extended Common Chunk, this size is 22 plus the number of bytes in the compressionName string.
  3985. numChannels    The number of audio channels contained in the sampled sound. A value of 1 indicates monophonic sound, a value of 2 indicates stereo sound, a value of 4 indicates four-channel sound, and so forth. 
  3986. numSampleFrames
  3987. The number of sample frames in the Sound Data Chunk. Note that this field contains the number of sample frames, not the number of bytes of data and not the number of sample points. For noncompressed sound data, the total number of sample points in the file is numChannels * numSampleFrames. 
  3988. sampleSize    The number of bits in each sample point of noncompressed sound data. The sampleSize field can contain any integer from 1 to 32. For compressed sound data, this field indicates the number of bits per sample in the original sound data, before compression.
  3989. sampleRate    The sample rate at which the sound is to be played back, in sample frames per second.
  3990. compressionType
  3991. The ID of the compression algorithm, if any, used on the sound data. Compression algorithms supplied by Apple have the following types:
  3992.                     CONST
  3993.                         NoneType                                = 'NONE';
  3994.                         ACE2Type                                = 'ACE2';
  3995.                         ACE8Type                                = 'ACE8';
  3996.                         MACE3Type                                = 'MAC3';
  3997.                         MACE6Type                                = 'MAC6';
  3998.     You can define your own compression types, but you should register them with Apple.
  3999. compressionName
  4000. A human-readable name for the compression algorithm ID specified in the compressionType field. If the number of bytes in this field is odd, then it is padded with the digit 0. Compression algorithms supplied by Apple have the following names:
  4001.                     CONST
  4002.                         NoneName                                = 'not compressed';
  4003.                         ACE2to1Name                                = 'ACE 2-to-1';
  4004.                         ACE8to3Name                                = 'ACE 8-to-3';
  4005.                         MACE3to1Name                                = 'MACE 3-to-1';
  4006.                         MACE6to1Name                                = 'MACE 6-to-1';
  4007.     You can define your own compression types, but you should register them with Apple.
  4008. Sound Data Chunks 
  4009.  
  4010. AIFF and AIFF-C files generally contain a Sound Data Chunk that contains the actual sampled-sound data. The SoundDataChunk data type defines a Sound Data Chunk.
  4011. TYPE SoundDataChunk =
  4012. RECORD
  4013.     ckID:                ID;                {'SSND'}
  4014.     ckSize:                LongInt;                {size of chunk data}
  4015.     offset:                LongInt;                {offset to sound data}
  4016.     blockSize:                LongInt;                {size of alignment blocks}
  4017. END;
  4018. Field descriptions
  4019. ckID    The ID of this chunk. For a Sound Data Chunk, this ID is 'SSND'.
  4020. ckSize    The size of the data portion of this chunk. This size does not include the 8 bytes occupied by the values in the ckID and the ckSize fields. 
  4021. offset    An offset (in bytes) to the beginning of the first sample frame in the chunk data. Most applications do not need to use the offset field and should set it to 0.
  4022. blockSize    The size (in bytes) of the blocks to which the sound data is aligned. This field is used in conjunction with the offset field for aligning sound data to blocks. As with the offset field, most applications do not need to use the blockSize field and should set it to 0.
  4023. The sampled-sound data follows the blockSize field. If the data following the blockSize field contains an odd number of bytes, a pad byte with a value of 0 is added at the end to preserve an even length for this chunk. If there is a pad byte, it is not included in the ckSize field. For information on the format of the sampled-sound data, see “Sound Files” on page 2-81. 
  4024. Version Records
  4025.  
  4026. The functions SndSoundManagerVersion and MACEVersion return version information using a version record. The NumVersion data type defines a version record.
  4027. TYPE NumVersion = 
  4028. PACKED RECORD
  4029. CASE INTEGER OF
  4030.  0:
  4031.     (majorRev:                        SignedByte;                    {major revision level in BCD}
  4032.     minorAndBugRev:                        SignedByte;                    {minor revision level}
  4033.     stage:                        SignedByte;                    {development stage}
  4034.     nonRelRev:                        SignedByte);                    {nonreleased revision level}
  4035.  1:
  4036.     (version:                        LongInt);                    {all 4 fields together}
  4037. END;
  4038. IMPORTANT
  4039. A version record has the same structure as the first four fields of a version resource (a resource of type 'vers'). See the chapter “Finder Interface” in Inside Macintosh: Macintosh Toolbox Essentials for complete information about version resources.s
  4040. Field descriptions
  4041. majorRev    The major revision level. This field is a signed byte in binary-coded decimal format.
  4042. minorAndBugRev
  4043. The minor revision level. This field is a signed byte in binary-coded decimal format.
  4044. stage    The development stage. You should use the following constants to specify a development stage:
  4045.                     CONST
  4046.                         developStage                        = $20;            {prealpha release}
  4047.                         alphaStage                        = $40;            {alpha release}
  4048.                         betaStage                        = $60;            {beta release}
  4049.                         finalStage                        = $80;            {final release}
  4050. nonRelRev    The revision level of a prereleased version.
  4051. version    A long integer that contains all four version fields.
  4052. Leftover Blocks
  4053.  
  4054. The leftOverSamples field of a compressed sound header contains a pointer to a leftover block, defined by the LeftOverBlock data type.
  4055. TYPE LeftOverBlock = 
  4056. RECORD
  4057.     count:                    LongInt;
  4058.     sampleArea:                    PACKED ARRAY[0..leftOverBlockSize - 1] OF Byte;
  4059. END;
  4060. Field descriptions
  4061. count    The number of bytes in the sampleArea field.
  4062. sampleArea    An array of bytes. This field contains samples that are truncated across invocations of the compression algorithm. The size of this field is defined by a constant.
  4063.                     CONST
  4064.                         leftOverBlockSize                                = 32;
  4065. State Blocks
  4066.  
  4067. The stateVars field of a compressed sound header contains a pointer to a state block, defined by the StateBlock data type.
  4068. TYPE StateBlock = 
  4069. RECORD
  4070.     stateVar:                        ARRAY[0..stateBlockSize - 1] OF Integer;
  4071. END;
  4072. Field descriptions
  4073. stateVar    An array of integers. This field contains state variables that need to be preserved across invocations of the compression algorithm. The size of this field is defined by a constant.
  4074.                     CONST
  4075.                         stateBlockSize                                = 64;
  4076. Sound Manager Routines
  4077.  
  4078. This section describes the routines provided by the Sound Manager. You can use these routines to
  4079. n    play sound resources
  4080. n    play sounds stored in files directly from disk
  4081. n    allocate and release sound channels
  4082. n    send commands to a sound channel
  4083. n    obtain information about the Sound Manager, a sound channel, all sound channels, or the system alert sound’s status
  4084. n    compress and expand audio data
  4085. n    manage the reading and writing of double sound buffers
  4086. The section “Application-Defined Routines” on page 2-151 describes routines that your application might need to define, including callback procedures, completion routines, and doubleback procedures.
  4087. Assembly-Language Note
  4088. Most Sound Manager routines are accessed through the _SoundDispatch selector. However, the SndAddModifier, SndControl, SndDisposeChannel, SndDoCommand, SndDoImmediate, SndNewChannel, and SndPlay functions and the SysBeep procedure are accessed through their own trap macros. See “Summary of the Sound Manager,” which begins on page 2-157, for a list of trap selector numbers.u
  4089. Playing Sound Resources
  4090.  
  4091. You can use the SysBeep procedure to play the system alert sound. Alert sounds are stored in the System file as format 1 'snd ' resources. You can use the SndPlay function to play the sounds that are stored in any 'snd ' resource, either format 1 or format 2.
  4092. The SysBeep and SndPlay routines are the highest-level sound routines that the Sound Manager provides. Depending on the needs of your application, you might be able to accomplish all desired sound-related activity simply by using SysBeep to produce the system alert sound or by using SndPlay to play other sounds that are stored as 'snd ' resources.
  4093. SysBeep
  4094.  
  4095. You can use the SysBeep procedure to play the system alert sound.
  4096. PROCEDURE SysBeep (duration: Integer);
  4097. duration    The duration (in ticks) of the resulting sound. This parameter is ignored except on a Macintosh Plus, Macintosh SE, or Macintosh Classic when the system alert sound is the Simple Beep. The recommended duration is 30 ticks, which equals one-half second.
  4098. DESCRIPTION
  4099. The SysBeep procedure causes the Sound Manager to play the system alert sound at its current volume. If necessary, the Sound Manager loads into memory the sound resource containing the system alert sound and links it to a sound channel. The user selects a system alert sound in the Alert Sounds subpanel of the Sound control panel.
  4100. The volume of the sound produced depends on the current setting of the system alert sound volume, which the user can adjust in the Alert Sounds subpanel of the Sound control panel. The system alert sound volume can also be read and set by calling the GetSysBeepVolume and SetSysBeepVolume routines. If the volume is set to 0 (silent) and the system alert sound is enabled, calling SysBeep causes the menu bar to blink once.
  4101. SPECIAL CONSIDERATIONS
  4102. Because the SysBeep procedure moves memory, you should not call it at interrupt time.
  4103. SEE ALSO
  4104. For information on enabling and disabling the system alert sound, see the description of SndGetSysBeepState and SndGetSysBeepState on page 2-137. For information on reading or adjusting the system alert sound volume, see “Controlling Volume Levels” beginning on page 2-139.
  4105. SndPlay
  4106.  
  4107. You can use the SndPlay function to play a sound resource that your application has loaded into memory.
  4108. FUNCTION SndPlay (chan: SndChannelPtr; sndHdl: Handle; 
  4109.                         async: Boolean): OSErr;
  4110. chan    A pointer to a valid sound channel. You can pass NIL instead of a pointer to a sound channel if you want the Sound Manager to internally allocate a sound channel in your application’s heap zone.
  4111. sndHdl    A handle to the sound resource to play.
  4112. async    A Boolean value that indicates whether the sound should be played asynchronously (TRUE) or synchronously (FALSE). This parameter is ignored (and the sound plays synchronously) if NIL is passed in the first parameter.
  4113. DESCRIPTION
  4114. The SndPlay function attempts to play the sound located at sndHdl, which is expected to have the structure of a format 1 or format 2 'snd ' resource. If the resource has not yet been loaded, the SndPlay function fails and returns the resProblem result code. 
  4115. All commands and data contained in the sound handle are then sent to the channel. Note that you can pass SndPlay a handle to some data created by calling the Sound Input Manager’s SndRecord function as well as a handle to an actual 'snd ' resource that you have loaded into memory.
  4116. sWARNING
  4117. In some versions of system software prior to system software version 7.0, the SndPlay function will not work properly with sound resources that specify the sound data type twice. This might happen if a resource specifies that a sound consists of sampled-sound data and an application does the same when creating a sound channel. For more information on this problem, see “Allocating Sound Channels” on page 2-20.s
  4118. The chan parameter is a pointer to a sound channel. If chan is not NIL, it is used as a valid channel. If chan is NIL, an internally allocated sound channel is used. If you do supply a sound channel pointer in the chan parameter, you can play the sound asynchronously. When a sound is played asynchronously, a callback procedure can be called when a callBackCmd command is processed by the channel. (This procedure is the callback procedure supplied to SndNewChannel.) See “Playing Sounds Asynchronously” on page 2-46 for more information on playing sounds asynchronously. The handle you pass in the sndHdl parameter must be locked for as long as the sound is playing asynchronously.
  4119. If a format 1 'snd ' resource does not specify which type of sound data is to be played, SndPlay defaults to square-wave data. SndPlay also supports format 2 'snd ' resources using sampled-sound data and a bufferCmd command. Note that to use SndPlay and sampled-sound data with a format 1 'snd ' resource, the resource must include a bufferCmd command.
  4120. SPECIAL CONSIDERATIONS
  4121. Because the SndPlay function moves memory, you should not call it at interrupt time.
  4122. RESULT CODESnoErr    0    No error    
  4123. notEnoughHardwareErr    –201    Insufficient hardware available    
  4124. resProblem    –204    Problem loading the resource    
  4125. badChannel    –205    Channel is corrupt or unusable    
  4126. badFormat    –206    Resource is corrupt or unusable    
  4127.  
  4128. SEE ALSO
  4129. For an example of how to play a sound resource using the SndPlay function, see the chapter “Introduction to Sound on the Macintosh” in this book.
  4130. For information on playing a sound resource without using the SndPlay function, see “Playing Sounds Using Low-Level Routines” on page 2-61.
  4131. Playing From Disk
  4132.  
  4133. Use the SndStartFilePlay, SndPauseFilePlay, and SndStopFilePlay functions to manage a continuous play from disk.
  4134. SndStartFilePlay
  4135.  
  4136. You can call the SndStartFilePlay function to initiate a play from disk.
  4137. FUNCTION SndStartFilePlay (chan: SndChannelPtr; fRefNum: Integer;
  4138.                                      resNum: Integer; bufferSize: LongInt;
  4139.                                      theBuffer: Ptr; 
  4140.                                     theSelection: AudioSelectionPtr; 
  4141.                                     theCompletion: ProcPtr; 
  4142.                                     async: Boolean): OSErr;
  4143. chan    A pointer to a valid sound channel. You can pass NIL instead of a pointer to a sound channel if you want the Sound Manager to internally allocate a sound channel in your application’s heap zone.
  4144. fRefNum    The file reference number of the AIFF or AIFF-C file to play. To play a sound resource rather than a sound file, this field should be 0.
  4145. resNum    The resource ID number of a sound resource to play. To play a sound file rather than a sound resource, this field should be 0.
  4146. bufferSize
  4147. The number of bytes of memory that the Sound Manager is to use for input buffering while reading in sound data. For SndStartFilePlay to execute successfully on the slowest Macintosh computers, use a buffer of at least 20,480 bytes. You can pass the value 0 to instruct the Sound Manager to allocate a buffer of the default size.
  4148. theBuffer    A pointer to a buffer that the Sound Manager should use for input buffering while reading in sound data. If this parameter is NIL, the Sound Manager allocates two buffers, each half the size of the value specified in the bufferSize parameter. If this parameter is not NIL, the buffer should be a nonrelocatable block of size bufferSize.
  4149. theSelection
  4150. A pointer to an audio selection record that specifies which portion of a sound should be played. You can pass NIL to specify that the Sound Manager should play the entire sound.
  4151. theCompletion
  4152. A pointer to a completion routine that the Sound Manager calls when the sound is finished playing. You can pass NIL to specify that the Sound Manager should not execute a completion routine. This field is useful only for asynchronous play.
  4153. async    A Boolean value that indicates whether the sound should be played asynchronously (TRUE) or synchronously (FALSE). You can play sound asynchronously only if you allocate your own sound channel (using SndNewChannel). If you pass NIL in the chan parameter and TRUE for this parameter, the SndStartFilePlay function returns the badChannel result code.
  4154. DESCRIPTION
  4155. The SndStartFilePlay function begins a continuous play from disk on a sound channel. The chan parameter is a pointer to the sound channel. If chan is not NIL, it is used as a valid channel. If chan is NIL, an internally allocated sound channel is used for play from disk. This internally allocated sound channel is not passed back to you. Because SndPauseFilePlay and SndStopFilePlay require a sound-channel pointer, you must allocate your own channel if you wish to use those routines.
  4156. The sounds you wish to play can be stored either in a file or in an 'snd ' resource. If you are playing a file, then fRefNum should be the file reference number of the file to be played and the parameter resNum should be set to 0. If you are playing an 'snd ' resource, then fRefNum should be set to 0 and resNum should be the resource ID number (not the file reference number) of the resource to play.
  4157. sWARNING
  4158. The SndStartFilePlay function might not play 'snd ' resources from disk correctly. In particular, the function will not execute correctly if any resource in the resource file containing the 'snd ' resource you wish to play has been changed through a call to the WriteResource procedure and you have not updated the resource file using the UpdateResFile procedure. To avoid this and other problems, you should use the SndStartFilePlay function to play only sound files.s
  4159. SPECIAL CONSIDERATIONS
  4160. Because the SndStartFilePlay function moves memory, you should not call it at interrupt time.
  4161. ASSEMBLY-LANGUAGE INFORMATION
  4162. The trap macro and routine selector for the SndStartFilePlay function are
  4163. Trap macro    Selector    
  4164. _SoundDispatch    $0D000008    
  4165.  
  4166. RESULT CODESnoErr    0    No error    
  4167. notEnoughHardwareErr    –201    Insufficient hardware available    
  4168. queueFull    –203    No room in the queue    
  4169. badChannel    –205    Channel is corrupt or unusable    
  4170. badFormat    –206    Resource is corrupt or unusable    
  4171. notEnoughBufferSpace    –207    Insufficient memory available    
  4172. badFileFormat    –208    File is corrupt or unusable, or not AIFF or AIFF-C    
  4173. channelBusy    –209    Channel is busy    
  4174. buffersTooSmall    –210    Buffer is too small    
  4175. siInvalidCompression    –223    Invalid compression type    
  4176.  
  4177. SEE ALSO
  4178. For an example of how to play a sound file, see the chapter “Introduction to Sound on the Macintosh” in this book.
  4179. For information on the format of a completion routine, see “Completion Routines” on page 2-151.
  4180. SndPauseFilePlay
  4181.  
  4182. You can use the SndPauseFilePlay function to toggle the state of a play from disk in progress, just as you might use the pause button on an audiocassette tape player to temporarily pause and then resume play. 
  4183. FUNCTION SndPauseFilePlay (chan: SndChannelPtr): OSErr;
  4184. chan    A pointer to a valid sound channel currently processing a play from disk initiated by a call to the SndStartFilePlay function.
  4185. DESCRIPTION
  4186. The SndPauseFilePlay function suspends the play from disk on the channel specified by the chan parameter if that play from disk is not already paused; the function resumes play if the play from disk is already paused.
  4187. The SndPauseFilePlay function is used in conjunction with SndStopFilePlay to control play from disk on a sound channel. Note that this call can be made only if your application has already called SndStartFilePlay with a valid sound channel. You cannot use this function with a synchronous call to SndStartFilePlay because, in that case, program control does not return to the caller until after the sound has completely finished playing.
  4188. If the channel specified by the chan parameter is not being used for play from disk, then SndPauseFilePlay returns the result code channelNotBusy. If the channel is busy and paused, then play from disk is resumed. If the channel is busy and the channel is not paused, then play from disk is suspended.
  4189. SPECIAL CONSIDERATIONS
  4190. You can call the SndPauseFilePlay function at interrupt time.
  4191. ASSEMBLY-LANGUAGE INFORMATION
  4192. The trap macro and routine selector for the SndPauseFilePlay function are
  4193. Trap macro    Selector    
  4194. _SoundDispatch    $02040008    
  4195.  
  4196. RESULT CODESnoErr    0    No error    
  4197. queueFull    –203    No room in the queue    
  4198. badChannel    –205    Channel is corrupt or unusable    
  4199. channelNotBusy    –211    Channel not currently used    
  4200.  
  4201. SndStopFilePlay
  4202.  
  4203. You can use SndStopFilePlay to stop an asynchronous play from disk.
  4204. FUNCTION SndStopFilePlay (chan: SndChannelPtr; 
  4205.                                     quietNow: Boolean): OSErr;
  4206. chan    A pointer to a valid sound channel currently processing a play from disk initiated by a call to the SndStartFilePlay function.
  4207. quietNow    A Boolean value that indicates whether the play from disk should be stopped immediately (TRUE) or when it completes execution (FALSE).
  4208. DESCRIPTION
  4209. The SndStopFilePlay function either can stop an asynchronous play from disk immediately or can take control of the CPU until a play from disk finishes. The SndStopFilePlay function does not return until all asynchronous file I/O calls have completed and any internally allocated memory has been released. If async is FALSE, then SndStopFilePlay lets the sound complete normally and returns only after the sound has completed, all asynchronous file I/O calls have completed, and any internal allocated memory has been released.
  4210. For example, you might use the function to stop the playing of a sound file if the user selects an option that turns off sound output while the file is already playing. In that case, you would pass TRUE to quietNow. Alternatively, you might have started a sound playing asynchronously so that you could perform other tasks while the sound plays. But you might then finish those other tasks and want to convert the play from disk into a synchronous play. By passing FALSE to quietNow, you effectively achieve that.
  4211. SPECIAL CONSIDERATIONS
  4212. Because the SndStopFilePlay function might move memory, you should not call it at interrupt time.
  4213. ASSEMBLY-LANGUAGE INFORMATION
  4214. The trap macro and routine selector for the SndStopFilePlay function are
  4215. Trap macro    Selector    
  4216. _SoundDispatch    $03080008    
  4217.  
  4218. RESULT CODESnoErr    0    No error    
  4219. badChannel    –205    Channel is corrupt or unusable    
  4220.  
  4221. Allocating and Releasing Sound Channels
  4222.  
  4223. If you use a high-level Sound Manager routine to play sounds, you might be able to let the Sound Manager internally allocate a sound channel. However, to use low-level sound commands or to take full advantage of the Sound Manager’s high-level routines, you must allocate your own sound channels. The SndNewChannel function allows your application to allocate a new sound channel, and the SndDisposeChannel function allows your application to dispose of it.
  4224. SndNewChannel
  4225.  
  4226. You can use the SndNewChannel function to allocate a new sound channel.
  4227. FUNCTION SndNewChannel (VAR chan: SndChannelPtr; synth: Integer; 
  4228.                                 init: LongInt; userRoutine: ProcPtr): 
  4229.                                 OSErr;
  4230. chan    A pointer to a sound channel record. You can pass a pointer whose value is NIL to force the Sound Manager to allocate the sound channel record internally.
  4231. synth    The sound data type you intend to play on this channel. If you do not want to specify a specific data type, pass 0 in this parameter. You might do this if you plan to use the channel to play a single sound resource that itself specifies the sound’s data type.
  4232. init    The desired initialization parameters for the channel. If you cannot determine what types of sounds you will be playing on the channel, pass 0 in this parameter. Only sounds defined by wave-table data and sampled-sound data currently use the init options. You can use the Gestalt function to determine if a sound feature (such as stereo output) is supported by a particular computer.
  4233. userRoutine
  4234. A pointer to a callback procedure that the Sound Manager executes whenever it receives a callBackCmd command. If you pass NIL as the userRoutine parameter, then any callBackCmd commands sent to this channel are ignored. 
  4235. DESCRIPTION
  4236. The SndNewChannel function internally allocates memory to store a queue of sound commands. If you pass a pointer to NIL as the chan parameter, the function also allocates a sound channel record in your application’s heap and returns a pointer to that record. If you do not pass a pointer to NIL as the chan parameter, then that parameter must contain a pointer to a sound channel record.
  4237. If you pass a pointer to NIL as the chan parameter, then the amount of memory the SndNewChannel function allocates to store the sound commands is enough to store 128 sound commands. However, if you pass a pointer to the sound channel record rather than a pointer to NIL, the amount of memory allocated is determined by the qLength field of the sound channel record. Thus, if you wish to control the size of the sound queue, you must allocate your own sound channel record. Regardless of whether you allocate your own sound channel record, the Sound Manager allocates memory for the sound command queue internally.
  4238. The synth parameter specifies the sound data type you intend to play on this channel. You can use these constants to specify the data type:
  4239. CONST
  4240.     squareWaveSynth                                 = 1;                {square-wave data}
  4241.     waveTableSynth                                = 3;                {wave-table data}
  4242.     sampledSynth                                 = 5;                {sampled-sound data}
  4243. In Sound Manager versions earlier than version 3.0, only one data type can be produced at any one time. As a result, SndNewChannel may fail if you attempt to open a channel specifying a data type other than the one currently being played.
  4244. To specify a sound output device other than the current sound output device, pass the value kUseOptionalOutputDevice in the synth parameter and the signature of the desired sound output device component in the init parameter.
  4245. CONST
  4246.     kUseOptionalOutputDevice                                        = -1;
  4247. The ability to redirect output away from the current sound output device is intended for use by specialized applications that need to use a specific sound output device. In general, your application should always send sound to the current sound output device selected by the user.
  4248. SPECIAL CONSIDERATIONS
  4249. Because the SndNewChannel function allocates memory, you should not call it at interrupt time.
  4250. RESULT CODESnoErr    0    No error    
  4251. resProblem    –204    Problem loading the resource    
  4252. badChannel    –205    Channel is corrupt or unusable    
  4253.  
  4254. SEE ALSO
  4255. For an example of a routine that uses the SndNewChannel function, see Listing 2-1 on page 2-20.
  4256. For information on the format of a callback procedure, see “Callback Procedures” on page 2-152.
  4257. SndDisposeChannel 
  4258.  
  4259. If you allocate a sound channel by calling the SndNewChannel function, you must release the memory it occupies by calling the SndDisposeChannel function. 
  4260. FUNCTION SndDisposeChannel (chan: SndChannelPtr; 
  4261.                                         quietNow: Boolean): OSErr;
  4262. chan    A pointer to a valid sound channel record.
  4263. quietNow    A Boolean value that indicates whether the channel should be disposed immediately (TRUE) or after sound stops playing (FALSE).
  4264. DESCRIPTION
  4265. The SndDisposeChannel function disposes of the queue of sound commands associated with the sound channel specified in the chan parameter. If your application created its own sound channel record in memory or installed a sound as a voice in a channel, the Sound Manager does not dispose of that memory. The Sound Manager also does not release memory associated with a sound resource that you have played on a channel. You might use the userInfo field of the sound channel record to store the address of a sound handle you wish to release before disposing of the sound channel itself.
  4266. The SndDisposeChannel function can dispose of a channel immediately or wait until the queued commands are processed. If quietNow is set to TRUE, a flushCmd command and then a quietCmd command are sent to the channel bypassing the command queue. This removes all commands, stops any sound in progress, and closes the channel. If quietNow is set to FALSE, then the Sound Manager issues a quietCmd command only; it does not bypass the command queue, and it waits until the quietCmd command is processed before disposing of the channel.
  4267. SPECIAL CONSIDERATIONS
  4268. Because the SndDisposeChannel function might dispose of memory, you should not call it at interrupt time.
  4269. RESULT CODESnoErr    0    No error    
  4270. badChannel    –205    Channel is corrupt or unusable    
  4271.  
  4272. Sending Commands to a Sound Channel
  4273.  
  4274. Once a sound channel is opened, you can send commands to that channel by issuing requests with the SndDoCommand and SndDoImmediate functions.
  4275. The section “Sound Command Numbers” beginning on page 2-92 lists the sound commands that you can send using SndDoCommand, SndDoImmediate, or (in several cases) SndControl.
  4276. SndDoCommand
  4277.  
  4278. You can queue a command in a sound channel by calling the SndDoCommand function.
  4279. FUNCTION SndDoCommand (chan: SndChannelPtr; cmd: SndCommand; 
  4280.                                 noWait: Boolean): OSErr;
  4281. chan    A pointer to a valid sound channel.
  4282. cmd    A sound command to be sent to the channel specified in the chan parameter.
  4283. noWait    A flag indicating whether the Sound Manager should wait for a free space in a full queue (FALSE) or whether it should return immediately with a queueFull result code if the queue is full (TRUE).
  4284. DESCRIPTION
  4285. The SndDoCommand function sends the sound command specified in the cmd parameter to the end of the command queue of the channel specified in the chan parameter.
  4286. The noWait parameter has meaning only if a sound channel’s queue of sound commands is full. If the noWait parameter is set to FALSE and the queue is full, the Sound Manager waits until there is space to add the command, thus preventing your application from doing other processing. If noWait is set to TRUE and the queue is full, the Sound Manager does not send the command and returns the queueFull result code.
  4287. SPECIAL CONSIDERATIONS
  4288. Whether SndDoCommand moves memory depends on the particular sound command you’re sending it. Most of the available sound commands do not cause SndDoCommand to move memory and can therefore be issued at interrupt time. Moreover, you can sometimes safely send commands at interrupt time that would otherwise cause memory to move if you’ve previously issued the soundCmd sound command to preconfigure the channel at noninterrupt time.
  4289. RESULT CODESnoErr    0    No error    
  4290. queueFull    –203    No room in the queue    
  4291. badChannel    –205    Channel is corrupt or unusable    
  4292.  
  4293. SEE ALSO
  4294. For an example of a routine that uses the SndDoCommand function, see Listing 2-15 on page 2-42.
  4295. SndDoImmediate
  4296.  
  4297. You can use the SndDoImmediate function to place a sound command in front of a sound channel’s command queue.
  4298. FUNCTION SndDoImmediate (chan: SndChannelPtr; cmd: SndCommand): 
  4299.                                     OSErr;
  4300. chan    A pointer to a sound channel.
  4301. cmd    A sound command to be sent to the channel specified in the chan parameter.
  4302. DESCRIPTION
  4303. The SndDoImmediate function operates much like SndDoCommand, except that it bypasses the existing command queue of the sound channel and sends the specified command directly to the Sound Manager for immediate processing. This routine also overrides any waitCmd, pauseCmd, or syncCmd commands that might have already been processed. However, other commands already received by the Sound Manager will not be interrupted by the SndDoImmediate function (although a quietCmd command sent via SndDoImmediate will quiet a sound already playing).
  4304. SPECIAL CONSIDERATIONS
  4305. Whether SndDoImmediate moves memory depends on the particular sound command you’re sending it. Most of the available sound commands do not cause SndDoImmediate to move memory and can therefore be issued at interrupt time. Moreover, you can sometimes safely send commands at interrupt time that would otherwise cause memory to move if you’ve previously issued the soundCmd sound command to preconfigure the channel at noninterrupt time.
  4306. RESULT CODESnoErr    0    No error    
  4307. badChannel    –205    Channel is corrupt or unusable    
  4308.  
  4309. SEE ALSO
  4310. For an example of a routine that uses the SndDoImmediate function, see Listing 2-4 on page 2-26.
  4311. Obtaining Information
  4312.  
  4313. To obtain information about whether a computer supports certain sound features, you should use the Gestalt function, documented in Inside Macintosh: Operating System Utilities. Sometimes, however, you might need information the Gestalt function is not able to provide. The Sound Manager provides a number of routines that you can use to obtain additional sound-related information.
  4314. You can obtain the version numbers of the Sound Manager and the MACE tools by calling the SndSoundManagerVersion and MACEVersion functions, respectively. You can obtain information about a sound channel and about all sound channels by calling the SndControl, SndChannelStatus, and SndManagerStatus functions, respectively.
  4315. The Sound Manager includes two routines—SndGetSysBeepState and SndSetSysBeepState—that allow you to determine and alter the status of the system alert sound.
  4316. To play a sound resource using low-level Sound Manager routines, you need the address of the sound header stored in the sound resource. Sound Manager versions 3.0 and later provide the GetSoundHeaderOffset function that you can use to obtain that information.
  4317. SndSoundManagerVersion
  4318.  
  4319. You can use SndSoundManagerVersion to determine the version of the Sound Manager tools available on a computer.
  4320. FUNCTION SndSoundManagerVersion: NumVersion;
  4321. DESCRIPTION
  4322. The SndSoundManagerVersion function returns a version number that contains the same information as in the first 4 bytes of a 'vers' resource. You might use the SndSoundManagerVersion function to determine if a computer has the enhanced Sound Manager, which is necessary for multichannel sound and for continuous plays from disk.
  4323. SPECIAL CONSIDERATIONS
  4324. You can call the SndSoundManagerVersion function at interrupt time.
  4325. ASSEMBLY-LANGUAGE INFORMATION
  4326. The trap macro and routine selector for the SndSoundManagerVersion function are
  4327. Trap macro    Selector    
  4328. _SoundDispatch    $000C0008    
  4329.  
  4330. SEE ALSO
  4331. For information on how to use the SndSoundManagerVersion function to determine whether the enhanced Sound Manager is available, see “Obtaining Version Information” on page 2-34.
  4332. MACEVersion
  4333.  
  4334. You can use MACEVersion to determine the version of the MACE tools available on a machine.
  4335. FUNCTION MACEVersion: NumVersion;
  4336. DESCRIPTION
  4337. The MACEVersion function returns a version number that contains the same information as in the first 4 bytes of a 'vers' resource.
  4338. SPECIAL CONSIDERATIONS
  4339. You can call the MACEVersion function at interrupt time.
  4340. ASSEMBLY-LANGUAGE INFORMATION
  4341. The trap macro and routine selector for the MACEVersion function are
  4342. Trap macro    Selector    
  4343. _SoundDispatch    $00000010     
  4344.  
  4345. SndControl
  4346.  
  4347. You can obtain information about a sound data type by using the SndControl function. In Sound Manager version 3.0 and later, however, you virtually never need to call SndControl. The capabilities that SndControl provides are either provided by the Gestalt function or are no longer supported. The SndControl function is documented here for completeness only.
  4348. FUNCTION SndControl (id: Integer; VAR cmd: SndCommand): OSErr;
  4349. id    The sound data type you want to get information about.
  4350. cmd    A sound command.
  4351. DESCRIPTION
  4352. The SndControl function sends a control command directly to the Sound Manager to get information about a specific data type. The available data types are specified by constants:
  4353. CONST
  4354.     squareWaveSynth                        = 1;            {square-wave data}
  4355.     waveTableSynth                        = 3;            {wave-table data}
  4356.     sampledSynth                        = 5;            {sampled-sound data}
  4357. You can call SndControl even if no channel has been created for the type of data you want to get information about. SndControl can be used with the availableCmd or versionCmd sound commands to request information. The requested information is returned in the sound command record specified by the cmd parameter.
  4358. IMPORTANT
  4359. The SndControl function can indicate only whether a particular data format supports some feature (for example, stereo output), not whether the available sound hardware also supports that feature. In general, you should use the Gestalt function to determine whether the sound features you need are available in the current operating environment.s
  4360. In Sound Manager version 2.0, you can also use the totalLoadCmd and loadCmd commands to get information about the amount of CPU time consumed by sound-related processing. However, these commands are not very accurate and are not supported by version 3.0 and later.
  4361. SPECIAL CONSIDERATIONS
  4362. You should not call the SndControl function at interrupt time.
  4363. RESULT CODESnoErr    0    No error    
  4364.  
  4365. SEE ALSO
  4366. See the list of sound commands in “Sound Command Numbers” beginning on page 2-92 for a complete description of the sound commands supported by SndControl.
  4367. SndChannelStatus
  4368.  
  4369. You can use the SndChannelStatus function to determine the status of a sound channel.
  4370. FUNCTION SndChannelStatus (chan: SndChannelPtr; 
  4371.                                         theLength: Integer; 
  4372.                                         theStatus: SCStatusPtr): OSErr;
  4373. chan    A pointer to a valid sound channel.
  4374. theLength    The size in bytes of the sound channel status record. You should set this field to SizeOf(SCStatus).
  4375. theStatus    A pointer to a sound channel status record.
  4376. DESCRIPTION
  4377. If the SndChannelStatus function executes successfully, the fields of the record specified by theStatus accurately describe the sound channel specified by chan.
  4378. SPECIAL CONSIDERATIONS
  4379. You can call the SndChannelStatus function at interrupt time.
  4380. ASSEMBLY-LANGUAGE INFORMATION
  4381. The trap macro and routine selector for the SndChannelStatus function are
  4382. Trap macro    Selector    
  4383. _SoundDispatch    $00100008    
  4384.  
  4385. RESULT CODESnoErr    0    No error    
  4386. paramErr    –50    A parameter is incorrect    
  4387. badChannel    –205    Channel is corrupt or unusable    
  4388.  
  4389. SEE ALSO
  4390. For information on the structure of a sound channel status record, see “Sound Channel Status Records” on page 2-101.
  4391. SndManagerStatus
  4392.  
  4393. You can use the SndManagerStatus function to determine information about all sound channels currently allocated.
  4394. FUNCTION SndManagerStatus (theLength: Integer; 
  4395.                                         theStatus: SMStatusPtr): OSErr;
  4396. theLength    The size in bytes of the Sound Manager status record. You should set this field to SizeOf(SMStatus).
  4397. theStatus    A pointer to a Sound Manager status record.
  4398. DESCRIPTION
  4399. The SndManagerStatus function determines information about all currently allocated sound channels. If the SndManagerStatus function executes successfully, the fields of the record specified by theStatus accurately describe the current status of the Sound Manager.
  4400. SPECIAL CONSIDERATIONS
  4401. You can call the SndManagerStatus function at interrupt time.
  4402. ASSEMBLY-LANGUAGE INFORMATION
  4403. The trap macro and routine selector for the SndManagerStatus function are
  4404. Trap macro    Selector    
  4405. _SoundDispatch    $00140008    
  4406.  
  4407. RESULT CODESnoErr    0    No error    
  4408.  
  4409. SndGetSysBeepState
  4410.  
  4411. You can use the SndGetSysBeepState procedure to determine if the system alert sound is enabled.
  4412. PROCEDURE SndGetSysBeepState (VAR sysBeepState: Integer);
  4413. sysBeepState
  4414. On exit, the state of the system alert sound.
  4415. DESCRIPTION
  4416. The SndGetSysBeepState procedure returns one of two states in the sysBeepState parameter, either the sysBeepDisable or the sysBeepEnable constant.
  4417. CONST
  4418.     sysBeepDisable                        = $0000;                {system alert sound disabled}
  4419.     sysBeepEnable                        = $0001;                {system alert sound enabled}
  4420. SPECIAL CONSIDERATIONS
  4421. You can call the SndGetSysBeepState procedure at interrupt time.
  4422. ASSEMBLY-LANGUAGE INFORMATION
  4423. The trap macro and routine selector for the SndGetSysBeepState procedure are
  4424. Trap macro    Selector    
  4425. _SoundDispatch    $00180008    
  4426.  
  4427. SndSetSysBeepState
  4428.  
  4429. You can use the SndSetSysBeepState function to set the state of the system alert sound.
  4430. FUNCTION SndSetSysBeepState (sysBeepState: Integer): OSErr;
  4431. sysBeepState
  4432. The desired state of the system alert sound.
  4433. DESCRIPTION
  4434. You can use the SndSetSysBeepState function to temporarily disable the system alert sound while you play a sound and then enable the alert sound when you are done. The sysBeepState parameter should be set to either sysBeepDisable or sysBeepEnable.
  4435. If your application disables the system alert sound, be sure to enable it when your application gets a suspend event.
  4436. SPECIAL CONSIDERATIONS
  4437. You can call the SndSetSysBeepState function at interrupt time.
  4438. ASSEMBLY-LANGUAGE INFORMATION
  4439. The trap macro and routine selector for the SndSetSysBeepState function are
  4440. Trap macro    Selector    
  4441. _SoundDispatch    $001C0008    
  4442.  
  4443. RESULT CODESnoErr    0    No error    
  4444. paramErr    –50    A parameter is incorrect    
  4445.  
  4446. GetSoundHeaderOffset
  4447.  
  4448. You can use the GetSoundHeaderOffset function to get the offset from the beginning of a sound resource to the embedded sound header.
  4449. FUNCTION GetSoundHeaderOffset (sndHdl: Handle; 
  4450.                                             VAR offset: LongInt): OSErr;
  4451. sndHdl    A handle to a sound resource.
  4452. offset    On exit, the offset from the beginning of the sound resource specified by the sndHdl parameter to the beginning of the sound header within that sound resource.
  4453. DESCRIPTION
  4454. The GetSoundHeaderOffset function returns, in the offset parameter, the number of bytes from the beginning of the sound resource specified by the sndHdl parameter to the sound header that is contained within that resource. You might need this information if you want to use the address of that sound header in a sound command (such as the soundCmd or bufferCmd sound command).
  4455. The handle passed to GetSoundHeaderOffset does not have to be locked.
  4456. SPECIAL CONSIDERATIONS
  4457. The GetSoundHeaderOffset function is available only in version 3.0 and later of the Sound Manager. See “Obtaining a Pointer to a Sound Header” beginning on page 2-57 for a function you can call in earlier versions of the Sound Manager to obtain the same information.
  4458. You can call the GetSoundHeaderOffset function at interrupt time.
  4459. ASSEMBLY-LANGUAGE INFORMATION
  4460. The trap macro and routine selector for the GetSoundHeaderOffset function are
  4461. Trap macro    Selector    
  4462. _SoundDispatch    $04040024    
  4463.  
  4464. RESULT CODESnoErr    0    No error    
  4465. badFormat    –206    Resource is corrupt or unusable    
  4466.  
  4467. SEE ALSO
  4468. See Listing 2-27 on page 2-57 for an example of calling GetSoundHeaderOffset.
  4469. Controlling Volume Levels
  4470.  
  4471. You can use the GetSysBeepVolume and SetSysBeepVolume functions to get and set the volume level of the system alert sound. You can use GetDefaultOutputVolume and SetDefaultOutputVolume to get and set the default output volume for a particular output device.
  4472. IMPORTANT
  4473. These four functions are available only in Sound Manager version 3.0 and later.s
  4474. With all of these functions, you specify a volume with a 16-bit value, where 0 represents no volume (that is, silence) and 256 (hexadecimal $0100) represents full volume. The right and left volumes of a stereo sound are encoded as the high word and the low word, respectively, of a 32-bit value. Moreover, it’s possible to overdrive a particular volume level if you need to amplify a low signal. For example, the long word $02000200 specifies a volume level of twice full volume on both the left and right channels of a stereo sound.
  4475. In addition to the four functions described in this section, Sound Manager version 3.0 introduces two new sound commands, getVolumeCmd and volumeCmd, that you can use to get and set the volume of a particular sound channel. See page 2-96 for details on these two sound commands; see “Managing Sound Volumes” beginning on page 2-31 for a code listing that uses the volumeCmd command.
  4476. GetSysBeepVolume
  4477.  
  4478. You can use the GetSysBeepVolume function to determine the current volume of the system alert sound.
  4479. FUNCTION GetSysBeepVolume (VAR level: LongInt): OSErr;
  4480. level    On exit, the current volume level of the system alert sound.
  4481. DESCRIPTION
  4482. The GetSysBeepVolume function returns, in the level parameter, the current volume level of the system alert sound. The values returned in the high and low words of the level parameter range from 0 (silence) to $0100 (full volume).
  4483. SPECIAL CONSIDERATIONS
  4484. The GetSysBeepVolume function is available only in versions 3.0 and later of the Sound Manager. You can call this function at interrupt time.
  4485. ASSEMBLY-LANGUAGE INFORMATION
  4486. The trap macro and routine selector for the GetSysBeepVolume function are
  4487. Trap macro    Selector    
  4488. _SoundDispatch    $02240024    
  4489.  
  4490. RESULT CODESnoErr    0    No error    
  4491.  
  4492. SetSysBeepVolume
  4493.  
  4494. You can use the SetSysBeepVolume function to set the current volume of the system alert sound.
  4495. FUNCTION SetSysBeepVolume (level: LongInt): OSErr;
  4496. level    The desired volume level of the system alert sound.
  4497. DESCRIPTION
  4498. The SetSysBeepVolume function sets the current volume level of the system alert sound. The values you can specify in the high and low words of the level parameter range from 0 (silence) to $0100 (full volume). Any calls to the SysBeep procedure use the volume set by the most recent call to SetSysBeepVolume.
  4499. SPECIAL CONSIDERATIONS
  4500. The SetSysBeepVolume function is available only in versions 3.0 and later of the Sound Manager. You can call this function at interrupt time.
  4501. ASSEMBLY-LANGUAGE INFORMATION
  4502. The trap macro and routine selector for the SetSysBeepVolume function are
  4503. Trap macro    Selector    
  4504. _SoundDispatch    $02280024    
  4505.  
  4506. RESULT CODESnoErr    0    No error    
  4507.  
  4508. GetDefaultOutputVolume
  4509.  
  4510. You can use the GetDefaultOutputVolume function to determine the default volume of a sound output device.
  4511. FUNCTION GetDefaultOutputVolume (VAR level: LongInt): OSErr;
  4512. level    On exit, the default volume level of a sound output device.
  4513. DESCRIPTION
  4514. The GetDefaultOutputVolume function returns, in the level parameter, the default volume of a sound output device. The values returned in the high and low words of the level parameter range from 0 (silence) to $0100 (full volume).
  4515. SPECIAL CONSIDERATIONS
  4516. The GetDefaultOutputVolume function is available only in versions 3.0 and later of the Sound Manager. You can call this function at interrupt time.
  4517. ASSEMBLY-LANGUAGE INFORMATION
  4518. The trap macro and routine selector for the GetDefaultOutputVolume function are
  4519. Trap macro    Selector    
  4520. _SoundDispatch    $022C0024    
  4521.  
  4522. RESULT CODESnoErr    0    No error    
  4523.  
  4524. SetDefaultOutputVolume
  4525.  
  4526. You can use the SetDefaultOutputVolume function to set the default volume of a sound output device.
  4527. FUNCTION SetDefaultOutputVolume (level: LongInt): OSErr;
  4528. level    The desired default volume level of a sound output device.
  4529. DESCRIPTION
  4530. The SetDefaultOutputVolume function sets the default volume of a sound output device. The values you can specify in the high and low words of the level parameter range from 0 (silence) to $0100 (full volume).
  4531. SPECIAL CONSIDERATIONS
  4532. The SetDefaultOutputVolume function is available only in versions 3.0 and later of the Sound Manager. You can call this function at interrupt time.
  4533. ASSEMBLY-LANGUAGE INFORMATION
  4534. The trap macro and routine selector for the SetDefaultOutputVolume function are
  4535. Trap macro    Selector    
  4536. _SoundDispatch    $02300024    
  4537.  
  4538. RESULT CODESnoErr    0    No error    
  4539.  
  4540. Compressing and Expanding Audio Data
  4541.  
  4542. You can use the procedures Comp3to1 and Comp6to1 to compress sound data. You can use the procedures Exp1to3 and Exp1to6 to expand compressed audio data.
  4543. Comp3to1
  4544.  
  4545. You can use the Comp3to1 procedure to compress sound data at a ratio of 3:1.
  4546. PROCEDURE Comp3to1 (inBuffer: Ptr; outBuffer: Ptr; cnt: LongInt;
  4547.                             inState: Ptr; outState: Ptr; 
  4548.                             numChannels: LongInt; whichChannel: LongInt);
  4549. inBuffer    A pointer to a buffer of samples to be compressed.
  4550. outBuffer    A pointer to a buffer where the samples are to be written.
  4551. cnt    The number of samples to compress.
  4552. inState    A pointer to a 128-byte buffer from which the input state of the algorithm is read, or NIL. To initialize the algorithm, this buffer should be filled with zeros.
  4553. outState    A pointer to a 128-byte buffer to which the output state of the algorithm is written, or NIL. This buffer might be the same as that specified by the inState parameter.
  4554. numChannels
  4555. The number of channels in the buffer pointed to by the inBuffer parameter.
  4556. whichChannel
  4557. The channel to compress, when numChannels is greater than 1. This parameter must be in the range of 1 to numChannels.
  4558. DESCRIPTION
  4559. The Comp3to1 procedure compresses cnt samples of sound stored in the buffer specified by inBuffer and places the result in the buffer specified by outBuffer, which must be at least cnt/3 bytes in size. The original samples can be monophonic or include multiple channels of sound, but they must be in 8-bit offset binary format. Also, if numChannels is greater than 1, then the noncompressed sound must be stored in interleaved format on a sample basis.
  4560. If you compress polyphonic sound, you retain only one channel of sound, which you specify in the whichChannel parameter. Thus, if you use the Comp3to1 procedure to compress three-channel sound, you will have effectively compressed the sound to one-ninth its original size in bytes. To retain multiple channels of sound after compression, you must call the Comp3to1 procedure for each channel to be compressed and then interleave the compressed sound data on a packet basis.
  4561. The Comp3to1 procedure compresses every 48 bytes of sound data to exactly 16 bytes of compressed sound data and compresses remaining bytes to no more than one-third the original size.
  4562. You can use the inState and outState parameters to allow the MACE compression routines to preserve information about algorithms across calls. Alternatively, you may pass NIL state buffers and let the Sound Manager allocate the buffers internally.
  4563. SPECIAL CONSIDERATIONS
  4564. Because the Comp3to1 procedure might allocate and dispose of memory, you should not call it at interrupt time.
  4565. ASSEMBLY-LANGUAGE INFORMATION
  4566. The trap macro and routine selector for the Comp3to1 procedure are
  4567. Trap macro    Selector    
  4568. _SoundDispatch    $00040010    
  4569.  
  4570. Comp6to1
  4571.  
  4572. You can use the Comp6to1 procedure to compress sound data at a ratio of 6:1.
  4573. PROCEDURE Comp6to1 (inBuffer: Ptr; outBuffer: Ptr; cnt: LongInt;
  4574.                             inState: Ptr; outState: Ptr; 
  4575.                             numChannels: LongInt; whichChannel: LongInt);
  4576. inBuffer    A pointer to a buffer of samples to be compressed.
  4577. outBuffer    A pointer to a buffer where the samples are to be written.
  4578. cnt    The number of samples to compress.
  4579. inState    A pointer to a 128-byte buffer from which the input state of the algorithm is read, or NIL. To initialize the algorithm, this buffer should be filled with zeros.
  4580. outState    A pointer to a 128-byte buffer to which the output state of the algorithm is written, or NIL. This buffer might be the same as that specified by the inState parameter.
  4581. numChannels
  4582. The number of channels in the buffer pointed to by the inBuffer parameter.
  4583. whichChannel
  4584. The channel to compress, when numChannels is greater than 1. This parameter must be in the range of 1 to numChannels.
  4585. DESCRIPTION
  4586. The Comp6to1 procedure compresses cnt samples of sound stored in the buffer specified by inBuffer and places the result in the buffer specified by outBuffer, which must be at least cnt/6 bytes in size. The Comp6to1 procedure works much like the Comp3to1 procedure, but compresses every 48 bytes of sound data to exactly 8 bytes of compressed sound data and compresses remaining bytes to no more than one-sixth the original size.
  4587. SPECIAL CONSIDERATIONS
  4588. Because the Comp6to1 procedure might allocate and dispose of memory, you should not call it at interrupt time.
  4589. ASSEMBLY-LANGUAGE INFORMATION
  4590. The trap macro and routine selector for the Comp6to1 procedure are
  4591. Trap macro    Selector    
  4592. _SoundDispatch    $000C0010    
  4593.  
  4594. Exp1to3
  4595.  
  4596. You can use the Exp1to3 procedure to expand a buffer of sound samples you previously have compressed with the Comp3to1 procedure.
  4597. PROCEDURE Exp1to3 (inBuffer: Ptr; outBuffer: Ptr; cnt: LongInt;
  4598.                          inState: Ptr; outState: Ptr; 
  4599.                          numChannels: LongInt; whichChannel: LongInt);
  4600. inBuffer    A pointer to a buffer of packets to be expanded.
  4601. outBuffer    A pointer to a buffer where the expanded samples will be written.
  4602. cnt    The number of packets to expand.
  4603. inState    A pointer to a 128-byte buffer from which the input state of the algorithm is read, or NIL. To initialize the algorithm, this buffer should be filled with zeros.
  4604. outState    A pointer to a 128-byte buffer to which the output state of the algorithm is written, or NIL. This buffer might be the same as that specified by the inState parameter.
  4605. numChannels
  4606. The number of channels in the buffer pointed to by the inBuffer parameter.
  4607. whichChannel
  4608. The channel to expand, when numChannels is greater than 1. This parameter must be in the range of 1 to numChannels.
  4609. DESCRIPTION
  4610. The Exp1to3 procedure expands cnt packets of sound stored in the buffer specified by inBuffer and places the result in the buffer specified by outBuffer, whose size must be at least cnt packets * 2 bytes per packet * 3, or cnt * 6 bytes. If numChannels is greater than 1, then the compressed sound must be stored in interleaved format on a packet basis.
  4611. If you expand compressed sound data that includes multiple sound channels, you retain only one channel of sound, which you specify in the whichChannel parameter. Thus, if you use the Exp1to3 procedure to expand three-channel sound, the output buffer will be the same size as the input buffer since only one channel is retained. To retain multiple channels of sound after expansion, you must call the Exp1to3 procedure for each channel to be expanded and then interleave the expanded sound data on a sample basis.
  4612. The Exp1to3 procedure expands every packet of sampled-sound data to exactly 6 bytes.
  4613. You can use the inState and outState parameters to allow the MACE compression routines to preserve information about algorithms across calls. Alternatively, you may pass NIL state buffers and let the Sound Manager allocate the buffers internally.
  4614. SPECIAL CONSIDERATIONS
  4615. Because the Exp1to3 procedure might allocate memory, you should not call it at interrupt time.
  4616. ASSEMBLY-LANGUAGE INFORMATION
  4617. The trap macro and routine selector for the Exp1to3 procedure are
  4618. Trap macro    Selector    
  4619. _SoundDispatch    $00080010    
  4620.  
  4621. Exp1to6
  4622.  
  4623. You can use the Exp1to6 procedure to expand a buffer of sound samples you previously have compressed with the Comp6to1 procedure.
  4624. PROCEDURE Exp1to6 (inBuffer: Ptr; outBuffer: Ptr; cnt: LongInt;
  4625.                          inState: Ptr; outState: Ptr; 
  4626.                          numChannels: LongInt; whichChannel: LongInt);
  4627. inBuffer    A pointer to a buffer of packets to be expanded.
  4628. outBuffer    A pointer to a buffer where the expanded samples will be written.
  4629. cnt    The number of packets to expand.
  4630. inState    A pointer to a 128-byte buffer from which the input state of the algorithm is read, or NIL. To initialize the algorithm, this buffer should be filled with zeros.
  4631. outState    A pointer to a 128-byte buffer to which the output state of the algorithm is written, or NIL. This buffer might be the same as that specified by the inState parameter.
  4632. numChannels
  4633. The number of channels in the buffer pointed to by the inBuffer parameter.
  4634. whichChannel
  4635. The channel to expand, when numChannels is greater than 1. This parameter must be in the range of 1 to numChannels.
  4636. DESCRIPTION
  4637. The Exp1to6 procedure expands cnt packets of sound stored in the buffer specified by inBuffer and places the result in the buffer specified by outBuffer, whose size must be at least cnt packets * 1 byte per packet * 6, or cnt * 6 bytes. If numChannels is greater than 1, then the compressed sound must be stored in interleaved format on a packet basis. The Exp1to6 procedure works just like the Exp1to3 procedure, but expands 1-byte packets rather than 2-byte packets.
  4638. SPECIAL CONSIDERATIONS
  4639. Because the Exp1to6 procedure might allocate memory, you should not call it at interrupt time.
  4640. ASSEMBLY-LANGUAGE INFORMATION
  4641. The trap macro and routine selector for the Exp1to6 procedure are
  4642. Trap macro    Selector    
  4643. _SoundDispatch    $00100010    
  4644.  
  4645. Managing Double Buffers
  4646.  
  4647. If you wish to customize the double buffering algorithm that the Sound Manager uses to manage a play from disk, you can use the SndPlayDoubleBuffer function. The Sound Manager’s high-level play-from-disk routines make extensive use of this function.
  4648. SndPlayDoubleBuffer
  4649.  
  4650. The SndPlayDoubleBuffer function is a low-level routine that gives you maximum efficiency and control over double buffering while still maintaining compatibility with the Sound Manager.
  4651. FUNCTION SndPlayDoubleBuffer (chan: SndChannelPtr;
  4652.                             theParams: SndDoubleBufferHeaderPtr): OSErr;
  4653. chan    A pointer to a valid sound channel.
  4654. theParams    A pointer to a sound double buffer header record.
  4655. DESCRIPTION
  4656. The SndPlayDoubleBuffer function launches a low-level sound play using the information in the double buffer header record specified by theParams. After your application calls this function, the Sound Manager repeatedly calls the doubleback procedure you specify in the double buffer header record. The doubleback procedure then manages the filling of buffers of sound data from disk whenever one of the two buffers specified in the double buffer header record becomes exhausted.
  4657. SPECIAL CONSIDERATIONS
  4658. Because the SndPlayDoubleBuffer function might move memory, you should not call it at interrupt time.
  4659. You can use the SndPlayDoubleBuffer function only on a Macintosh computer that supports the play-from-disk routines. For information on how to determine whether a computer supports these routines, see “Testing for Multichannel Sound and Play-From-Disk Capabilities” on page 2-35.
  4660. ASSEMBLY-LANGUAGE INFORMATION
  4661. The trap macro and routine selector for the SndPlayDoubleBuffer function are
  4662. Trap macro    Selector    
  4663. _SoundDispatch    $00200008    
  4664.  
  4665. RESULT CODESnoErr    0    No error    
  4666. badChannel    –205    Channel is corrupt or unusable    
  4667.  
  4668. SEE ALSO
  4669. For information on the format of a doubleback procedure, see “Doubleback Procedures” on page 2-153.
  4670. Performing Unsigned Fixed-Point Arithmetic
  4671.  
  4672. This section describes the UnsignedFixMulDiv function provided by the Sound Manager that you can use to perform multiplication and division on unsigned fixed-point numbers.
  4673. UnsignedFixMulDiv
  4674.  
  4675. You can use the UnsignedFixMulDiv function to perform multiplications and divisions on unsigned fixed-point numbers. You’ll typically use it to calculate sample rates.
  4676. FUNCTION UnsignedFixMulDiv (value: UnsignedFixed; 
  4677.                                         multiplier: UnsignedFixed; 
  4678.                                         divisor: UnsignedFixed): 
  4679.                                         UnsignedFixed;
  4680. value    The value to be multiplied and divided.
  4681. multiplier
  4682. The multiplier to be applied to the value in the value parameter.
  4683. divisor    The divisor to be applied to the value in the value parameter.
  4684. DESCRIPTION
  4685. The UnsignedFixMulDiv function returns the fixed-point number that is the value of the value parameter, multiplied by the value in the multiplier parameter and divided by the value in the divisor parameter. Note that UnsignedFixMulDiv performs both operations before returning. If you want to perform only a multiplication or only a division, pass the value $00010000 for whichever parameter you want to ignore. For example, to determine the sample rate that is twice that of the 22 kHz rate, you can use UnsignedFixMulDiv as follows:
  4686. myNewRate := UnsignedFixMulDiv(rate22kHz, $00020000, $00010000);
  4687. Similarly, to determine the sample rate that is half that of the 44 kHz rate, you can use UnsignedFixMulDiv as follows:
  4688. myNewRate := UnsignedFixMulDiv(rate44kHz, $00010000, $00020000);
  4689. SPECIAL CONSIDERATIONS
  4690. The UnsignedFixMulDiv function is available only in versions 3.0 and later of the Sound Manager.
  4691. Linking Modifiers to Sound Channels
  4692.  
  4693. Early versions of the Sound Manager allowed application developers to use modifiers to alter sound commands before being processed by the Sound Manager. The Sound Manager no longer supports this capability. SndAddModifier is documented here for completeness only.
  4694. SndAddModifier
  4695.  
  4696. The Sound Manager previously used the SndAddModifier function to link modifiers to sound channels.
  4697. FUNCTION SndAddModifier (chan: SndChannelPtr; modifier: ProcPtr; 
  4698.                                  id: Integer; init: LongInt): OSErr;
  4699. chan    A pointer to a valid sound channel.
  4700. modifier    A pointer to a modifier function to be added to the sound channel specified by chan. This field is obsolete.
  4701. id    The resource ID of the modifier to be linked to the sound channel.
  4702. init    The initialization parameters for the sound channel specified by chan.
  4703. DESCRIPTION
  4704. The SndAddModifier function installs a modifier into an open channel specified in the chan parameter. The modifier parameter should be NIL, and the id parameter is the resource ID of the modifier to be linked to the sound channel. SndAddModifier causes the Sound Manager to load the specified 'snth' resource, lock it in memory, and link it to the channel specified.
  4705. IMPORTANT
  4706. The SndAddModifier function is for internal Sound Manager use only. You should not call it in your application.s 
  4707. The only supported use of the SndAddModifier function is to change the data type associated with a sound channel. For example, you can pass the constant sampledSynth in the id parameter to reconfigure a sound channel for sampled-sound data. You should, however, set a sound channel’s data type when you call SndNewChannel, not by calling SndAddModifier.
  4708. SPECIAL CONSIDERATIONS
  4709. You should not use the SndAddModifier function.
  4710. RESULT CODESnoErr    0    No error    
  4711. resProblem    –204    Problem loading the resource    
  4712. badChannel    –205    Channel is corrupt or unusable    
  4713.  
  4714. SEE ALSO
  4715. To modify sampled-sound data immediately before the Sound Manager plays it, you can customize double buffering routines so that your application can modify sampled-sound data when it fills a buffer of sound data for the Sound Manager to play. For more information, see “Using Double Buffers” on page 2-68.
  4716. To change the initialization options for a sound channel, you can use the reInitCmd command. For a description of that command, see “Sound Command Numbers” beginning on page 2-92.
  4717. Application-Defined Routines
  4718.  
  4719. The Sound Manager allows you to define a completion routine that execute when a play from disk finishes executing, a callback procedure that executes whenever your application issues the callBackCmd command, and a doubleback procedure that you must define if you wish to customize the double buffering of data during a play from disk.
  4720. Completion Routines
  4721.  
  4722. You can specify a completion routine as the seventh parameter to the SndStartFilePlay function. The completion routine executes when the sound file finishes playing (unless sound play was stopped by the SndStopFilePlay function).
  4723. MyCompletionRoutine
  4724.  
  4725. A Sound Manager completion routine has the following syntax:
  4726. PROCEDURE MyFilePlayCompletionRoutine (chan: SndChannelPtr);
  4727. chan    A pointer to the sound channel on which a play from disk has completed.
  4728. DESCRIPTION
  4729. The Sound Manager executes your completion routine when a play from disk on the channel specified by the chan parameter finishes. You might use the completion routine to set a global flag that alerts the application that it must dispose of the sound channel.
  4730. SPECIAL CONSIDERATIONS
  4731. A completion routine is called at interrupt time. It must not make any calls to the Memory Manager, either directly or indirectly. If your completion routine needs to access your application’s global variables, you must ensure that register A5 contains your application’s A5. (You can use the userInfo field of the sound channel pointed to by the chan parameter to pass that value to your completion routine.) 
  4732. ASSEMBLY-LANGUAGE INFORMATION
  4733. Because this routine is called at interrupt time, it must preserve all registers other than A0–A1 and D0–D2. 
  4734. SEE ALSO
  4735. For information on how you can use completion routines to help manage an asynchronous play from disk, see “Managing an Asynchronous Play From Disk” on page 2-52.
  4736. Callback Procedures 
  4737.  
  4738. You can specify a callback procedure as the fourth parameter to the SndNewChannel function. The callback procedure executes whenever the Sound Manager processes a callBackCmd command for the channel.
  4739. MyCallbackProcedure
  4740.  
  4741. A callback procedure has the following syntax:
  4742. PROCEDURE MyCallbackProcedure (theChan: SndChannelPtr; 
  4743.                                             theCmd: SndCommand);
  4744. theChan    A pointer to the sound channel on which a callBackCmd command was issued.
  4745. theCmd    The sound command record in which a callBackCmd command was issued.
  4746. DESCRIPTION
  4747. The Sound Manager executes the callback procedure associated with a sound channel whenever it processes a callBackCmd command for the channel. You can use a callback procedure to set a global flag that alerts the application that it must dispose of the sound channel. Or, you can use a callback procedure so that your application can synchronize a series of sound commands with other actions.
  4748. SPECIAL CONSIDERATIONS
  4749. A callback procedure is called at interrupt time. It must not make any calls to the Memory Manager, either directly or indirectly. If your callback procedure needs to access your application’s global variables, you must ensure that register A5 contains your application’s A5. (You can use the userInfo field of the sound channel pointed to by the theChan parameter or the param2 field of the sound command specified in the theCmd parameter to pass that value to your callback procedure.) 
  4750. ASSEMBLY-LANGUAGE INFORMATION
  4751. Because a callback procedure is called at interrupt time, it must preserve all registers other than A0–A1 and D0–D2. 
  4752. SEE ALSO
  4753. For information on how you can use callback procedures when playing sound asynchronously, see “Using Callback Procedures” on page 2-47.
  4754. Doubleback Procedures
  4755.  
  4756. If you wish to customize the double buffering of sound during a play from disk, you must use the SndPlayDoubleBuffer function and define a doubleback procedure. Doubleback procedures also give you the power to modify sampled-sound data immediately before the Sound Manager plays it.
  4757. MyDoubleBackProc
  4758.  
  4759. A doubleback procedure has the following syntax:
  4760. PROCEDURE MyDoubleBackProc (chan: SndChannelPtr;
  4761.                                     exhaustedBuffer: SndDoubleBufferPtr);
  4762. chan    A pointer to a sound channel on which a play from disk is executing.
  4763. exhaustedBuffer
  4764. A pointer to a sound double buffer record
  4765. DESCRIPTION
  4766. The Sound Manager calls the doubleback procedure associated with a play from disk whenever the Sound Manager has exhausted the buffer. As the doubleback procedure refills the buffer, the Sound Manager plays the other buffer. Your application might also call the doubleback procedure twice to fill both buffers before the initial call to SndPlayDoubleBuffer function.
  4767. When your doubleback procedure is called, it must
  4768. n    fill the buffer specified in the exhaustedBuffer parameter with the next set of sound frames that the Sound Manager must play
  4769. n    set the dbNumFrames field of the sound double buffer record to the number of frames in the buffer
  4770. n    set the dbBufferReady bit of the dbFlags field of the sound double buffer record
  4771. If your doubleback procedure fills the buffer with the last frames of sound that need to be played, then your procedure should set the dbLastBuffer bit of the dbFlags field of the sound double buffer record.
  4772. Your doubleback procedure might fill the buffer with data from any of several sources. For example, the doubleback procedure might compute the data, copy it from elsewhere in RAM, or read it from disk. A doubleback procedure can also read data from disk and then modify the data. This might be useful, for example, if you would like the Sound Manager to be able to play sampled-sound data stored in 16-bit binary offset format. Your doubleback procedure could translate the data to the 8-bit binary offset format that the Sound Manager can read before placing it in the buffer.
  4773. SPECIAL CONSIDERATIONS
  4774. A doubleback procedure is called at interrupt time. It must not make any calls to the Memory Manager, either directly or indirectly. If your callback procedure needs to access your application’s global variables, you must ensure that register A5 contains your application’s A5. (You can use one of the two long integers in the dbUserInfo field of the sound double buffer record specified by the exhaustedBuffer parameter to pass that value to your callback procedure.) 
  4775. ASSEMBLY-LANGUAGE INFORMATION
  4776. Because a doubleback procedure is called at interrupt time, it must preserve all registers other than A0–A1 and D0–D2. 
  4777. SEE ALSO
  4778. For an example of how you might use doubleback procedures, see “Using Double Buffers” on page 2-68.
  4779. Resources
  4780.  
  4781. This section describes the structure of format 1 and format 2 sound resources. For a more complete discussion of the structure of sound resources, see “Sound Resources” on page 2-74.
  4782. The Sound Resource
  4783.  
  4784. You can store sound commands and sound data as a resource with the resource type 'snd '. Resource IDs from 0 to 8191 are reserved by Apple Computer, Inc. You may use all other resource IDs for your 'snd ' resources.
  4785. You can use the GetResource function to search all open resource files for the first 'snd ' resource type with the given ID. The 'snd ' resource type defines a sound resource. Figure 2-8 shows the structure of a sound resource.
  4786. Figure 2-8    The 'snd ' resource type
  4787.  
  4788. Often, you can create a sound resource simply by using the SndRecord function, documented in the chapter “Introduction to Sound on the Macintosh” in this book. However, you can also define a sound resource manually. This is especially useful for sound resources that are simply series of sound commands and contain no sampled-sound data. Also, you might construct a sound resource that contains wave-table data manually. A sound resource contains the following elements:
  4789. n    Sound resource header. The gives information about the format of a sound resource, as explained below.
  4790. n    Number of sound commands. Following the sound resource header is a word indicating the number of sound commands contained in the resource.
  4791. n    Sound commands. Each sound command is 8 bytes, which includes 2 bytes that identify the command, 2 bytes for the command’s first parameter, and 4 bytes for the command’s second parameter. When a sound command contained in an 'snd ' resource has associated sound data, the high bit (defined by the dataOffsetFlag constant) should be set. This tells the Sound Manager that the value in the second parameter is an offset from the beginning of the resource and not a pointer to a memory location.
  4792. n    Sound data. For a format 1 'snd ' resource, this field might contain wave-table data or a sampled sound header that includes sampled-sound data. For a format 2 'snd ' resource, this field should contain a sampled sound header that includes sampled-sound data.
  4793. The format of the sound resource header differs depending on whether the 'snd ' resource is format 1 or format 2. Figure 2-9 illustrates the formats of the two types of sound resource header. Both sound headers begin with a format field, which defines the format of the sound resource as either $0001 or $0002.
  4794. Figure 2-9    The sound resource header
  4795.  
  4796. n    Format 1 sound resource header. For format 1 'snd ' resources, the sound resource header includes a word that indicates the number of data types to be sent to the sound channel. Because a sound channel cannot play more than one type of sound data, you should typically specify either $00 or $01 in this field. If you specify $01 or more, then the sound resource header contains both a word specifying the data type and a long word specifying the initialization options for each data type.
  4797. n    Format 2 sound resource header. For format 2 'snd ' resources, the sound resource header next includes a single word that the Sound Manager ignores. This word is known as the reference count field. Your application can use this field as it pleases.
  4798.  
  4799.  
  4800. Summary of the Sound Manager
  4801.  
  4802. Pascal Summary
  4803.  
  4804. Constants
  4805.  
  4806. CONST
  4807.     {Gestalt sound attributes selector and response bits}
  4808.     gestaltSoundAttr                                    = 'snd ';            {sound attributes selector}
  4809.     gestaltStereoCapability                                    = 0;            {built-in hw can play stereo sounds}
  4810.     gestaltStereoMixing                                    = 1;            {built-in hw mixes stereo to mono}
  4811.     gestaltSoundIOMgrPresent                                    = 3;            {sound input routines available}
  4812.     gestaltBuiltInSoundInput                                    = 4;            {built-in input hw available}
  4813.     gestaltHasSoundInputDevice                                    = 5;            {sound input device available}
  4814.     gestaltPlayAndRecord                                    = 6;            {built-in hw can play while recording}
  4815.     gestalt16BitSoundIO                                     = 7;            {built-in hw can handle 16-bit data}
  4816.     gestaltStereoInput                                     = 8;            {built-in hw can record stereo sounds}
  4817.     gestaltLineLevelInput                                     = 9;            {built-in input hw needs line level}
  4818.     gestaltSndPlayDoubleBuffer                                    = 10;            {play from disk routines available}
  4819.     gestaltMultiChannels                                    = 11;            {multiple channels of sound supported}
  4820.     gestalt16BitAudioSupport                                     = 12;            {16-bit audio data supported}
  4821.     {channel initialization parameters}
  4822.     initChanLeft                                    = $0002;            {left stereo channel}
  4823.     initChanRight                                    = $0003;            {right stereo channel}
  4824.     waveInitChannel0                                    = $0004;            {wave-table channel 0}
  4825.     waveInitChannel1                                    = $0005;            {wave-table channel 1}
  4826.     waveInitChanne12                                    = $0006;            {wave-table channel 2}
  4827.     waveInitChannel3                                    = $0007;            {wave-table channel 3}
  4828.     initMono                                    = $0080;            {monophonic channel}
  4829.     initStereo                                    = $00C0;            {stereo channel}
  4830.     initMACE3                                    = $0300;            {3:1 compression}
  4831.     initMACE6                                    = $0400;            {6:1 compression}
  4832.     initNoInterp                                    = $0004;            {no linear interpolation}
  4833.     initNoDrop                                    = $0008;            {no drop-sample conversion}
  4834.     {masks for channel attributes}
  4835.     initPanMask                                = $0003;                {mask for right/left pan values}
  4836.     initSRateMask                                = $0030;                {mask for sample rate values}
  4837.     initStereoMask                                = $00C0;                {mask for mono/stereo values}
  4838.     initCompMask                                = $FF00;                {mask for compression IDs}
  4839.     {sound data types}
  4840.     squareWaveSynth                                 = 1;                {square-wave data}
  4841.     waveTableSynth                                = 3;                {wave-table data}
  4842.     sampledSynth                                 = 5;                {sampled-sound data}
  4843.     {sound command numbers}
  4844.     nullCmd                                = 0;                {do nothing}
  4845.     quietCmd                                = 3;                {stop a sound that is playing}
  4846.     flushCmd                                = 4;                {flush a sound channel}
  4847.     reInitCmd                                = 5;                {reinitialize a sound channel}
  4848.     waitCmd                                = 10;                {suspend processing in a channel}
  4849.     pauseCmd                                = 11;                {pause processing in a channel}
  4850.     resumeCmd                                = 12;                {resume processing in a channel}
  4851.     callBackCmd                                = 13;                {execute a callback procedure}
  4852.     syncCmd                                = 14;                {synchronize channels}
  4853.     availableCmd                                = 24;                {see if initialization options }
  4854.                                                     { are supported}
  4855.     versionCmd                                = 25;                {determine version}
  4856.     totalLoadCmd                                = 26;                {report total CPU load}
  4857.     loadCmd                                = 27;                {report CPU load for a new channel}
  4858.     freqDurationCmd                                = 40;                {play a note for a duration}
  4859.     restCmd                                = 41;                {rest a channel for a duration}
  4860.     freqCmd                                = 42;                {change the pitch of a sound
  4861.     ampCmd                                = 43;                {change the amplitude of a sound}
  4862.     timbreCmd                                = 44;                {change the timbre of a sound}
  4863.     getAmpCmd                                = 45;                {get the amplitude of a sound}
  4864.     volumeCmd                                = 46;                {set volume}
  4865.     getVolumeCmd                                = 47;                {get volume}
  4866.     waveTableCmd                                = 60;                {install a wave table as a voice}
  4867.     soundCmd                                = 80;                {install a sampled sound as a voice}
  4868.     bufferCmd                                = 81;                {play a sampled sound}
  4869.     rateCmd                                = 82;                {set the pitch of a sampled sound}
  4870.     getRateCmd                                = 85;                {get the pitch of a sampled sound}
  4871.     {sampled sound header encoding options}
  4872.     stdSH                                = $00;                {standard sound header}
  4873.     extSH                                = $FF;                {extended sound header}
  4874.     cmpSH                                = $FE;                {compressed sound header}
  4875.     {size of data structures}
  4876.     stdQLength                                = 128;                {default size of standard sound }
  4877.                                                     { channel}
  4878.     {sound resource formats}
  4879.     firstSoundFormat                                = $0001;                {format 1 'snd ' resource}
  4880.     secondSoundFormat                                = $0002;                {format 2 'snd ' resource}
  4881.     {sound command mask}
  4882.     dataOffsetFlag                                = $8000;                {sound command data offset bit}
  4883.     {system beep states}
  4884.     sysBeepDisable                                = $0000;                {system alert sound disabled}
  4885.     sysBeepEnable                                = $0001;                {system alert sound enabled}
  4886.     {values for the unitType field in AudioSelection}
  4887.     unitTypeSeconds                                = $0000;                {seconds}
  4888.     unitTypeNoSelection                                = $FFFF;                {no selection}
  4889.     {double buffer status flags}
  4890.     dbBufferReady                                = $00000001;    {double buffer is filled}
  4891.     dbLastBuffer                                = $00000004;    {last double buffer to play}
  4892.     {values for the compressionID field of CmpSoundHeader}
  4893.     variableCompression                                = -2;                {variable-ratio compression}
  4894.     fixedCompression                                = -1;                {fixed-ratio compression}
  4895.     notCompressed                                = 0;                {noncompressed samples}
  4896.     threeToOne                                = 3;                {3:1 compressed samples}
  4897.     sixToOne                                = 4;                {6:1 compressed samples}
  4898.     {values for the packetSize field of CmpSoundHeader}
  4899.     sixToOnePacketSize                                = 8;                {packet size in bits for 6:1}
  4900.     threeToOnePacketSize                                = 16;                {packet size in bits for 3:1}
  4901.     {compression names and types}
  4902.     NoneName                                = 'not compressed';
  4903.     ACE2to1Name                                = 'ACE 2-to-1';
  4904.     ACE8to3Name                                = 'ACE 8-to-3';
  4905.     MACE3to1Name                                = 'MACE 3-to-1';
  4906.     MACE6to1Name                                = 'MACE 6-to-1';
  4907.     NoneType                                = 'NONE';
  4908.     ACE2Type                                = 'ACE2';
  4909.     ACE8Type                                = 'ACE8';
  4910.     MACE3Type                                = 'MAC3';
  4911.     MACE6Type                                = 'MAC6'
  4912.     {IDs for AIFF and AIFF-C files}
  4913.     AIFFID                                = 'AIFF';                {AIFF file}
  4914.     AIFCID                                = 'AIFC';                {AIFF-C file}
  4915.     {IDs for AIFF and AIFF-C file chunks}
  4916.     FormID                                = 'FORM';                {ID for Form Chunk}
  4917.     FormatVersionID                                = 'FVER';                {ID for Format Version Chunk}
  4918.     CommonID                                = 'COMM';                {ID for Common Chunk}
  4919.     SoundDataID                                = 'SSND';                {ID for Sound Data Chunk}
  4920.     MarkerID                                = 'MARK';                {ID for Marker Chunk}
  4921.     InstrumentID                                = 'INST';                {ID for Instrument Chunk}
  4922.     MIDIDataID                                = 'MIDI';                {ID for MIDI Data Chunk}
  4923.     AudioRecordingID                                = 'AESD';                {ID for Recording Chunk}
  4924.     ApplicationSpecificID                                = 'APPL';                {ID for Application Chunk}
  4925.     CommentID                                = 'COMT';                {ID for Comment Chunk}
  4926.     NameID                                = 'NAME';                {ID for Name Chunk}
  4927.     AuthorID                                = 'AUTH';                {ID for Author Chunk}
  4928.     CopyrightID                                = '(c) ';                {ID for Copyright Chunk}
  4929.     AnnotationID                                = 'ANNO';                {ID for Annotation Chunk}
  4930.     {version of AIFC format specification}
  4931.     AIFCVersion1                                = $A2805140;                {date of version creation}
  4932.     {MIDI note value for middle C}
  4933.     kMiddleC                                = 60;
  4934.     {ratio between frequencies of MIDI note values}
  4935.     twelfthRootTwo                                = 1.05946309434;
  4936.     {standard sampling rates}
  4937.     rate44khz                                = $AC440000;                    {44100.00000 in fixed-point}
  4938.     rate22khz                                = $56EE8BA3;                    {22254.54545 in fixed-point}
  4939.     rate22050hz                                = $56220000;                    {22050.00000 in fixed-point}
  4940.     rate11khz                                = $2B7745D1;                    {11127.27273 in fixed-point}
  4941.     rate11025hz                                = $2B110000;                    {11025.00000 in fixed-point}
  4942.     {constant for synth parameter of SndNewChannel}
  4943.     kUseOptionalOutputDevice                                        = -1;
  4944.     {volumes}
  4945.     kFullVolume                                        = $0100;
  4946.     kNoVolume                                        = 0;
  4947.     {development stages}
  4948.     developStage                                = $20;                    {prealpha release}
  4949.     alphaStage                                = $40;                    {alpha release}
  4950.     betaStage                                = $60;                    {beta release}
  4951.     finalStage                                = $80;                    {final release}
  4952.     {sizes of data buffers}
  4953.     stateBlockSize                                = 64;                    {size of state block buffer}
  4954.     leftOverBlockSize                                = 32;                    {size of leftover block buffer}
  4955. Data Types
  4956.  
  4957. Unsigned Fixed-Point Numbers
  4958. TYPE
  4959.     UnsignedFixed = LongInt;                                                {unsigned fixed-point number}
  4960. Times
  4961. TYPE
  4962.     Time = LongInt;                                                {in half-milliseconds}
  4963. Sound Command Record
  4964.     SndCommand =
  4965.     PACKED RECORD
  4966.         cmd:                        Integer;                    {command number}
  4967.         param1:                        Integer;                    {first parameter}
  4968.         param2:                        LongInt;                    {second parameter}
  4969.     END;
  4970. Audio Selection Record
  4971.     AudioSelection = 
  4972.     PACKED RECORD
  4973.         unitType:                        LongInt;                    {type of time unit}
  4974.         selStart:                        Fixed;                    {starting point of selection}
  4975.         selEnd:                        Fixed;                    {ending point of selection}
  4976.     END;
  4977.     AudioSelectionPtr = ^AudioSelection;
  4978. Sound Channel Status Record
  4979.     SCStatus =
  4980.     RECORD
  4981.         scStartTime:                            Fixed;                {starting time for play from disk}
  4982.         scEndTime:                            Fixed;                {ending time for play from disk}
  4983.         scCurrentTime:                            Fixed;                {current time for play from disk}
  4984.         scChannelBusy:                            Boolean;                {TRUE if channel is processing cmds}
  4985.         scChannelDisposed:                            Boolean;                {reserved}
  4986.         scChannelPaused:                            Boolean;                {TRUE if play from disk is paused}
  4987.         scUnused:                            Boolean;                {unused}
  4988.         scChannelAttributes:                            LongInt;                {attributes of this channel}
  4989.         scCPULoad:                            LongInt;                {CPU load for this channel}
  4990.     END;
  4991.     SCStatusPtr = ^SCStatus;
  4992. Sound Manager Status Record
  4993.     SMStatus =
  4994.     PACKED RECORD
  4995.         smMaxCPULoad:                        Integer;                    {maximum load on all channels}
  4996.         smNumChannels:                        Integer;                    {number of allocated channels}
  4997.         smCurCPULoad:                        Integer;                    {current load on all channels}
  4998.     END;
  4999.     SMStatusPtr = ^SMStatus;
  5000. Sound Channel Record
  5001.     SndChannel =
  5002.     PACKED RECORD
  5003.         nextChan:                        SndChannelPtr;                    {pointer to next channel}
  5004.         firstMod:                        Ptr;                    {used internally}
  5005.         callBack:                        ProcPtr;                    {pointer to callback procedure}
  5006.         userInfo        :                LongInt;                    {free for application's use}
  5007.         wait:                        LongInt;                    {used internally}
  5008.         cmdInProgress:                        SndCommand;                    {used internally}
  5009.         flags:                        Integer;                    {used internally}
  5010.         qLength:                        Integer;                    {used internally}
  5011.         qHead:                        Integer;                    {used internally}
  5012.         qTail:                        Integer;                    {used internally}
  5013.         queue:                        ARRAY[0..stdQLength-1] OF SndCommand;
  5014.     END;
  5015.     SndChannelPtr = ^SndChannel;
  5016. Sound Header Record
  5017.     SoundHeader =
  5018.     PACKED RECORD
  5019.         samplePtr:                        Ptr;                    {if NIL, samples in sampleArea}
  5020.         length:                        LongInt;                    {number of samples in array}
  5021.         sampleRate:                        Fixed;                    {sample rate}
  5022.         loopStart:                        LongInt;                    {loop point beginning}
  5023.         loopEnd:                        LongInt;                    {loop point ending}
  5024.         encode:                        Byte;                    {sample's encoding option}
  5025.         baseFrequency:                        Byte;                    {base frequency of sample}
  5026.         sampleArea:                        PACKED ARRAY[0..0] OF Byte;
  5027.     END;
  5028.     SoundHeaderPtr = ^SoundHeader;
  5029. Extended Sound Header Record
  5030.     ExtSoundHeader =
  5031.     PACKED RECORD
  5032.         samplePtr:                        Ptr;                    {if NIL, samples in sampleArea}
  5033.         numChannels:                        LongInt;                    {number of channels in sample}
  5034.         sampleRate:                        Fixed;                    {rate of original sample}
  5035.         loopStart:                        LongInt;                    {loop point beginning}
  5036.         loopEnd:                        LongInt;                    {loop point ending}
  5037.         encode:                        Byte;                    {sample's encoding option}
  5038.         baseFrequency:                        Byte;                    {base frequency of sample}
  5039.         numFrames:                        LongInt;                    {total number of frames}
  5040.         AIFFSampleRate:                        Extended80;                    {rate of original sample}
  5041.         markerChunk:                        Ptr;                    {reserved}
  5042.         instrumentChunks:                        Ptr;                    {pointer to instrument info}
  5043.         AESRecording:                        Ptr;                    {pointer to audio info}
  5044.         sampleSize:                        Integer;                    {number of bits per sample}
  5045.         futureUse1:                        Integer;                    {reserved}
  5046.         futureUse2:                        LongInt;                    {reserved}
  5047.         futureUse3:                        LongInt;                    {reserved}
  5048.         futureUse4:                        LongInt;                    {reserved}
  5049.         sampleArea:                        PACKED ARRAY[0..0] OF Byte;
  5050.     END;
  5051.     ExtSoundHeaderPtr = ^ExtSoundHeader;
  5052. Compressed Sound Header Record
  5053.     CmpSoundHeader =
  5054.     PACKED RECORD
  5055.         samplePtr:                        Ptr;                    {if NIL, samples in sampleArea}
  5056.         numChannels:                        LongInt;                    {number of channels in sample}
  5057.         sampleRate:                        Fixed;                    {rate of original sample}
  5058.         loopStart:                        LongInt;                    {loop point beginning}
  5059.         loopEnd:                        LongInt;                    {loop point ending}
  5060.         encode:                        Byte;                    {sample's encoding option}
  5061.         baseFrequency:                        Byte;                    {base freq. of original sample}
  5062.         numFrames:                        LongInt;                    {length of sample in frames}
  5063.         AIFFSampleRate:                        Extended80;                    {rate of original sample}
  5064.         markerChunk:                        Ptr;                    {reserved}
  5065.         format:                        OSType;                    {data format type}
  5066.         futureUse2:                        LongInt;                    {reserved}
  5067.         stateVars:                        StateBlockPtr;                    {pointer to StateBlock}
  5068.         leftOverSamples:                        LeftOverBlockPtr;                        
  5069.                                                     {pointer to LeftOverBlock}
  5070.         compressionID:                        Integer;                    {ID of compression algorithm}
  5071.         packetSize:                        Integer;                    {number of bits per packet}
  5072.         snthID:                        Integer;                    {unused}
  5073.         sampleSize:                        Integer;                    {bits in each sample point}
  5074.         sampleArea:                        PACKED ARRAY[0..0] OF Byte;
  5075.     END;
  5076.     CmpSoundHeaderPtr                     = ^CmpSoundHeader;
  5077. Sound Double Buffer Header Record
  5078.     SndDoubleBufferHeader =
  5079.     PACKED RECORD
  5080.         dbhNumChannels:                        Integer;                    {number of sound channels}
  5081.         dbhSampleSize:                        Integer;                    {sample size, if noncompressed}
  5082.         dbhCompressionID:                        Integer;                    {ID of compression algorithm}
  5083.         dbhPacketSize:                        Integer;                    {number of bits per packet}
  5084.         dbhSampleRate:                        Fixed;                    {sample rate}
  5085.         dbhBufferPtr:                        ARRAY[0..1] OF SndDoubleBufferPtr;
  5086.                                                     {pointers to SndDoubleBuffer}
  5087.         dbhDoubleBack:                        ProcPtr;                    {pointer to doubleback procedure}
  5088.     END;
  5089.     SndDoubleBufferHeaderPtr = ^SndDoubleBufferHeader;
  5090.     SndDoubleBufferHeader2 =
  5091.     PACKED RECORD
  5092.         dbhNumChannels:                        Integer;                    {number of sound channels}
  5093.         dbhSampleSize:                        Integer;                    {sample size, if noncompressed}
  5094.         dbhCompressionID:                        Integer;                    {ID of compression algorithm}
  5095.         dbhPacketSize:                        Integer;                    {number of bits per packet}
  5096.         dbhSampleRate:                        Fixed;                    {sample rate}
  5097.         dbhBufferPtr:                        ARRAY[0..1] OF SndDoubleBufferPtr;
  5098.                                                     {pointers to SndDoubleBuffer}
  5099.         dbhDoubleBack:                        ProcPtr;                    {pointer to doubleback procedure}
  5100.         dbhFormat:                        OSType;                    {signature of codec}
  5101.     END;
  5102.     SndDoubleBufferHeaderPtr2 = ^SndDoubleBufferHeader2;
  5103. Sound Double Buffer Record
  5104.     SndDoubleBuffer =
  5105.     PACKED RECORD
  5106.         dbNumFrames:                        LongInt;                    {number of frames in buffer}
  5107.         dbFlags:                        LongInt;                    {buffer status flags}
  5108.         dbUserInfo:                        ARRAY[0..1] OF LongInt;
  5109.                                                     {for application's use}
  5110.         dbSoundData:                        PACKED ARRAY[0..0] OF Byte;
  5111.                                                     {array of data}
  5112.     END;
  5113.     SndDoubleBufferPtr = ^SndDoubleBuffer;
  5114. Chunk Header
  5115.     ID = LongInt;                                                {chunk ID type}
  5116.     ChunkHeader =
  5117.     RECORD
  5118.         ckID:                        ID;                    {chunk type ID}
  5119.         ckSize:                        LongInt;                    {number of bytes of data}
  5120.     END;
  5121. Form Chunk
  5122.     ContainerChunk =
  5123.     RECORD
  5124.         ckID:                        ID;                    {'FORM'}
  5125.         ckSize:                        LongInt;                    {number of bytes of data}
  5126.         formType:                        ID;                    {type of file}
  5127.     END;
  5128. Format Version Chunk
  5129.     FormatVersionChunk =
  5130.     RECORD
  5131.         ckID:                        ID;                    {'FVER'}
  5132.         ckSize:                        LongInt;                    {4 bytes}
  5133.         timestamp:                        LongInt;                    {date of format version}
  5134.     END;
  5135. Common Chunk
  5136.     CommonChunk =
  5137.     RECORD
  5138.         ckID:                        ID;                    {'COMM'}
  5139.         ckSize:                        LongInt;                    {18 bytes}
  5140.         numChannels:                        Integer;                    {number of channels}
  5141.         numSampleFrames:                        LongInt;                    {number of sample frames}
  5142.         sampleSize:                        Integer;                    {number of bits per sample}
  5143.         sampleRate:                        Extended;                    {number of frames per second}
  5144.     END;
  5145. Extended Common Chunk
  5146.     ExtCommonChunk =
  5147.     RECORD
  5148.         ckID:                        ID;                    {'COMM'}
  5149.         ckSize:                        LongInt;                    {22 bytes + compression name}
  5150.         numChannels:                        Integer;                    {number of channels}
  5151.         numSampleFrames:                        LongInt;                    {number of sample frames}
  5152.         sampleSize:                        Integer;                    {number of bits per sample}
  5153.         sampleRate:                        Extended;                    {number of frames per second}
  5154.         compressionType:                        ID;                    {compression type ID}
  5155.         compressionName:                        PACKED ARRAY[0..0] OF Byte;
  5156.                                                     {compression type name}
  5157.     END;
  5158. Sound Data Chunk
  5159.     SoundDataChunk =
  5160.     RECORD
  5161.         ckID:                ID;                {'SSND'}
  5162.         ckSize:                LongInt;                {size of chunk data}
  5163.         offset:                LongInt;                {offset to sound data}
  5164.         blockSize:                LongInt;                {size of alignment blocks}
  5165.     END;
  5166. Version Record
  5167.     NumVersion = 
  5168.     PACKED RECORD
  5169.     CASE INTEGER OF
  5170.      0:
  5171.         (majorRev:                        SignedByte;                    {major revision level in BCD}
  5172.         minorAndBugRev:                        SignedByte;                    {minor revision level}
  5173.         stage:                        SignedByte;                    {development stage}
  5174.         nonRelRev:                        SignedByte);                    {nonreleased revision level}
  5175.      1:
  5176.         (version:                        LongInt);                    {all 4 fields together}
  5177.     END;
  5178. Leftover Block
  5179.     LeftOverBlock = 
  5180.     RECORD
  5181.         count:                    LongInt;
  5182.         sampleArea:                    PACKED ARRAY[0..leftOverBlockSize - 1] OF Byte;
  5183.     END;
  5184.     LeftOverBlockPtr = ^LeftOverBlock;
  5185. State Block
  5186.     StateBlock = 
  5187.     RECORD
  5188.         stateVar:                    ARRAY[0..stateBlockSize - 1] OF Integer;
  5189.     END;
  5190.     StateBlockPtr = ^StateBlock;
  5191. Sound Manager Routines
  5192.  
  5193. Playing Sound Resources
  5194. PROCEDURE SysBeep    (duration: Integer);
  5195. FUNCTION SndPlay    (chan: SndChannelPtr; sndHdl: Handle; 
  5196. async: Boolean): OSErr;
  5197. Playing From Disk
  5198. FUNCTION SndStartFilePlay    (chan: SndChannelPtr; fRefNum: Integer; 
  5199. resNum: Integer; bufferSize: LongInt; theBuffer: Ptr; 
  5200. theSelection: AudioSelectionPtr; theCompletion: ProcPtr; async: Boolean): OSErr;
  5201. FUNCTION SndPauseFilePlay    (chan: SndChannelPtr): OSErr;
  5202. FUNCTION SndStopFilePlay    (chan: SndChannelPtr; quietNow: Boolean): OSErr;
  5203. Allocating and Releasing Sound Channels
  5204. FUNCTION SndNewChannel    (VAR chan: SndChannelPtr; synth: Integer; 
  5205. init: LongInt; userRoutine: ProcPtr): OSErr;
  5206. FUNCTION SndDisposeChannel    (chan: SndChannelPtr; quietNow: Boolean): OSErr;
  5207. Sending Commands to a Sound Channel
  5208. FUNCTION SndDoCommand    (chan: SndChannelPtr; cmd: SndCommand; 
  5209. noWait: Boolean): OSErr;
  5210. FUNCTION SndDoImmediate    (chan: SndChannelPtr; cmd: SndCommand): OSErr;
  5211. Obtaining Information
  5212. FUNCTION SndSoundManagerVersion
  5213. : NumVersion;
  5214. FUNCTION MACEVersion    : NumVersion;
  5215. FUNCTION SndControl    (id: Integer; VAR cmd: SndCommand): OSErr;
  5216. FUNCTION SndChannelStatus    (chan: SndChannelPtr; theLength: Integer; 
  5217. theStatus: SCStatusPtr): OSErr;
  5218. FUNCTION SndManagerStatus    (theLength: Integer; theStatus: SMStatusPtr): OSErr;
  5219. PROCEDURE SndGetSysBeepState
  5220. (VAR sysBeepState: Integer);
  5221. FUNCTION SndSetSysBeepState
  5222. (sysBeepState: Integer): OSErr;
  5223. FUNCTION GetSoundHeaderOffset
  5224. (sndHdl: Handle; VAR offset: LongInt): OSErr;
  5225. Controlling Volume Levels
  5226. FUNCTION GetSysBeepVolume    (VAR level: LongInt): OSErr;
  5227. FUNCTION SetSysBeepVolume    (level: LongInt): OSErr;
  5228. FUNCTION GetDefaultOutputVolume
  5229. (VAR level: LongInt): OSErr;
  5230. FUNCTION SetDefaultOutputVolume
  5231. (level: LongInt): OSErr;
  5232. Compressing and Expanding Audio Data
  5233. PROCEDURE Comp3to1    (inBuffer: Ptr; outBuffer: Ptr; cnt: LongInt; inState: Ptr; outState: Ptr; 
  5234. numChannels: LongInt; whichChannel: LongInt);
  5235. PROCEDURE Comp6to1    (inBuffer: Ptr; outBuffer: Ptr; cnt: LongInt; 
  5236. inState: Ptr; outState: Ptr; 
  5237. numChannels: LongInt; whichChannel: LongInt);
  5238. PROCEDURE Exp1to3    (inBuffer: Ptr; outBuffer: Ptr; cnt: LongInt; 
  5239. inState: Ptr; outState: Ptr; 
  5240. numChannels: LongInt; whichChannel: LongInt);
  5241. PROCEDURE Exp1to6    (inBuffer: Ptr; outBuffer: Ptr; cnt: LongInt; inState: Ptr; outState: Ptr; 
  5242. numChannels: LongInt; whichChannel: LongInt);
  5243. Managing Double Buffers
  5244. FUNCTION SndPlayDoubleBuffer
  5245. (chan: SndChannelPtr; 
  5246. theParams: SndDoubleBufferHeaderPtr): OSErr;
  5247. Performing Unsigned Fixed-Point Arithmetic
  5248. FUNCTION UnsignedFixMulDiv    (value: UnsignedFixed; 
  5249. multiplier: UnsignedFixed; 
  5250. divisor: UnsignedFixed): UnsignedFixed;
  5251. Linking Modifiers to Sound Channels
  5252. FUNCTION SndAddModifier    (chan: SndChannelPtr; modifier: ProcPtr; 
  5253. id: Integer; init: LongInt): OSErr;
  5254. Application-Defined Routines
  5255.  
  5256. PROCEDURE MyFilePlayCompletionRoutine
  5257. (chan: SndChannelPtr);
  5258. PROCEDURE MyCallback    (chan: SndChannelPtr; cmd: SndCommand);
  5259. PROCEDURE MyDoubleBackProc    (chan: SndChannelPtr; 
  5260. doubleBufferPtr: SndDoubleBufferPtr);
  5261. C Summary
  5262.  
  5263. Constants
  5264.  
  5265. /*Gestalt sound attributes selector and response bits*/
  5266. #define gestaltSoundAttr                                     'snd '            /*sound attributes selector*/
  5267. enum {
  5268.     gestaltStereoCapability                                    = 0,        /*built-in hw can play stereo sounds*/
  5269.     gestaltStereoMixing                                    = 1,        /*built-in hw mixes stereo to mono*/
  5270.     gestaltSoundIOMgrPresent                                    = 3,        /*sound input routines available*/
  5271.     gestaltBuiltInSoundInput                                    = 4,        /*built-in input hw available*/
  5272.     gestaltHasSoundInputDevice                                    = 5,        /*sound input device available*/
  5273.     gestaltPlayAndRecord                                    = 6,        /*built-in hw can play while recording*/
  5274.     gestalt16BitSoundIO                                     = 7,        /*built-in hw can handle 16-bit data*/
  5275.     gestaltStereoInput                                     = 8,        /*built-in hw can record stereo sounds*/
  5276.     gestaltLineLevelInput                                     = 9,        /*built-in input hw needs line level*/
  5277.     gestaltSndPlayDoubleBuffer                                    = 10,        /*play from disk routines available*/
  5278.     gestaltMultiChannels                                    = 11,        /*multiple channels of sound supported*/
  5279.     gestalt16BitAudioSupport                                     = 12        /*16-bit audio data supported*/
  5280. };
  5281. /*channel initialization parameters*/
  5282. enum {
  5283.     initChanLeft                                = 0x0002,                /*left stereo channel*/
  5284.     initChanRight                                = 0x0003,                /*right stereo channel*/
  5285.     initMono                                = 0x0080,                /*monophonic channel*/
  5286.     initStereo                                = 0x00C0,                /*stereo channel*/
  5287.     initMACE3                                = 0x0300,                /*3:1 compression*/
  5288.     initMACE6                                = 0x0400,                /*6:1 compression*/
  5289.     initNoInterp                                = 0x0004,                /*no linear interpolation*/
  5290.     initNoDrop                                = 0x0008                /*no drop-sample conversion*/
  5291. };
  5292. /*wave channel initialization parameters*/
  5293. enum {
  5294.     waveInitChannel0                                = 0x04,                /*wave-table channel 0*/
  5295.     waveInitChannel1                                = 0x05,                /*wave-table channel 1*/
  5296.     waveInitChannel2                                = 0x06,                /*wave-table channel 2*/
  5297.     waveInitChannel3                                = 0x07,                /*wave-table channel 3*/
  5298.     waveInitChannelMask                                = 0x07                /*mask for wave-table parameters*/
  5299. };
  5300. /*masks for channel attributes*/
  5301. enum {
  5302.     initPanMask                                = 0x0003,                /*mask for left/right pan values*/
  5303.     initSRateMask                                = 0x0030,                /*mask for sample rate values*/
  5304.     initStereoMask                                = 0x00C0,                /*mask for mono/stereo values*/
  5305.     initCompMask                                = 0xFF00                /*mask for compression IDs*/
  5306. };
  5307. /*sound data types*/
  5308. enum {
  5309.     squareWaveSynth                                = 1,                /*square-wave data*/
  5310.     waveTableSynth                                = 3,                /*wave-table data*/
  5311.     sampledSynth                                = 5                /*sampled-sound data*/
  5312. };
  5313. /*sound command numbers*/
  5314. enum {
  5315.     nullCmd                                = 0,                /*do nothing*/
  5316.     quietCmd                                = 3,                /*stop a sound that is playing*/
  5317.     flushCmd                                = 4,                /*flush a sound channel*/
  5318.     reInitCmd                                = 5,                /*reinitialize a sound channel*/
  5319.     waitCmd                                = 10,                /*suspend processing in a channel*/
  5320.     pauseCmd                                = 11,                /*pause processing in a channel*/
  5321.     resumeCmd                                = 12,                /*resume processing in a channel*/
  5322.     callBackCmd                                = 13,                /*execute a callback procedure*/
  5323.     syncCmd                                = 14,                /*synchronize channels*/
  5324.     availableCmd                                = 24,                /*see if initialization options */
  5325.                                                     /* are supported*/
  5326.     versionCmd                                = 25,                /*determine version*/
  5327.     totalLoadCmd                                = 26,                /*report total CPU load*/
  5328.     loadCmd                                = 27,                /*report CPU load for a new channel*/
  5329.     freqDurationCmd                                = 40,                /*play a note for a duration*/
  5330.     restCmd                                = 41,                /*rest a channel for a duration*/
  5331.     freqCmd                                = 42,                /*change the pitch of a sound*/
  5332.     ampCmd                                = 43,                /*change the amplitude of a sound*/
  5333.     timbreCmd                                = 44,                /*change the timbre of a sound*/
  5334.     getAmpCmd                                = 45,                /*get the amplitude of a sound*/
  5335.     volumeCmd                                = 46,                /*set volume*/
  5336.     getVolumeCmd                                = 47,                /*get volume*/
  5337.     waveTableCmd                                = 60,                /*install a wave table as a voice*/
  5338.     soundCmd                                = 80,                /*install a sampled sound as a voice*/
  5339.     bufferCmd                                = 81,                /*play a sampled sound*/
  5340.     rateCmd                                = 82,                /*set the pitch of a sampled sound*/
  5341.     getRateCmd                                = 85                /*get the pitch of a sampled sound*/
  5342. };
  5343. /*sampled sound header encoding options*/
  5344. enum {
  5345.     stdSH                                = 0x00,                /*standard sound header*/
  5346.     extSH                                = 0xFF,                /*extended sound header*/
  5347.     cmpSH                                = 0xFE                /*compressed sound header*/
  5348. };
  5349. /*size of data structures*/
  5350. enum {
  5351.     stdQLength                                = 128                /*default size of sound channel*/
  5352. };
  5353. /*sound resource formats*/
  5354. enum {
  5355.     firstSoundFormat                                = 0x0001,                /*format 1 'snd ' resource*/
  5356.     secondSoundFormat                                = 0x0002                /*format 2 'snd ' resource*/
  5357. };
  5358. /*sound command mask*/
  5359. enum {
  5360.     dataOffsetFlag                                = 0x8000                /*sound command data offset bit*/
  5361. };
  5362. /*system beep states*/
  5363. enum {
  5364.     sysBeepDisable                                = 0x0000,                /*system alert sound disabled*/
  5365.     sysBeepEnable                                = 0x0001                /*system alert sound enabled*/
  5366. };
  5367. /*values for the unitType field in AudioSelection*/
  5368. enum {
  5369.     unitTypeSeconds                                = 0x0000,                /*seconds*/
  5370.     unitTypeNoSelection                                = 0xFFFF                /*no selection*/
  5371. };
  5372. /*double buffer status flags*/
  5373. enum {
  5374.     dbBufferReady                                = 0x00000001,                    /*double buffer is filled*/
  5375.     dbLastBuffer                                = 0x00000004                    /*last double buffer to play*/
  5376. };
  5377. /*values for the compressionID field of CmpSoundHeader*/
  5378. enum {
  5379.     variableCompression                                = -2,                /*variable-ratio compression*/
  5380.     fixedCompression                                = -1,                /*fixed-ratio compression*/
  5381.     notCompressed                                = 0,                /*noncompressed samples*/
  5382.     threeToOne                                = 3,                /*3:1 compressed samples*/
  5383.     sixToOne                                = 4                /*6:1 compressed samples*/
  5384. };
  5385. /*values for the packetSize field of CmpSoundHeader*/
  5386. enum {
  5387.     sixToOnePacketSize                                = 8,                /*packet size in bits for 6:1*/
  5388.     threeToOnePacketSize                                = 16                /*packet size in bits for 3:1*/
  5389. };
  5390. /*compression names and types*/
  5391. #define NoneName                                        "\pnot compressed"
  5392. #define ACE2to1Name                                        "\pACE 2-to-1"
  5393. #define ACE8to3Name                                        "\pACE 8-to-3"
  5394. #define MACE3to1Name                                        "\pMACE 3-to-1"
  5395. #define MACE6to1Name                                        "\pMACE 6-to-1"
  5396. #define NoneType                                        'NONE'
  5397. #define ACE2Type                                        'ACE2'
  5398. #define ACE8Type                                        'ACE8'
  5399. #define MACE3Type                                        'MAC3'
  5400. #define MACE6Type                                        'MAC6'
  5401. /*IDs for AIFF and AIFF-C files*/
  5402. #define AIFFID                                        'AIFF'            /*AIFF file*/
  5403. #define AIFCID                                        'AIFC'            /*AIFF-C file*/
  5404. /*IDs for AIFF and AIFF-C file chunks*/
  5405. #define FORMID                                        'FORM'            /*ID for Form Chunk*/
  5406. #define FormatVersionID                                        'FVER'            /*ID for Format Version Chunk*/
  5407. #define CommonID                                        'COMM'            /*ID for Common Chunk*/
  5408. #define SoundDataID                                        'SSND'            /*ID for Sound Data Chunk*/
  5409. #define MarkerID                                        'MARK'            /*ID for Marker Chunk*/
  5410. #define InstrumentID                                        'INST'            /*ID for Instrument Chunk*/
  5411. #define MIDIDataID                                        'MIDI'            /*ID for MIDI Data Chunk*/
  5412. #define AudioRecordingID                                        'AESD'            /*ID for Recording Chunk*/
  5413. #define ApplicationSpecificID                                        'APPL'            /*ID for Application Chunk*/
  5414. #define CommentID                                        'COMT'            /*ID for Comment Chunk*/
  5415. #define NameID                                        'NAME'            /*ID for Name Chunk*/
  5416. #define AuthorID                                        'AUTH'            /*ID for Author Chunk*/
  5417. #define CopyrightID                                        '(c) '            /*ID for Copyright Chunk*/
  5418. #define AnnotationID                                        'ANNO'            /*ID for Annotation Chunk*/
  5419. /*version of AIFC format specification*/
  5420. #define AIFCVersion1                                        0xA2805140
  5421.                                                     /*date of version creation*/
  5422. /*MIDI note value for middle C*/
  5423. enum {
  5424.     kMiddleC                                = 60
  5425. };
  5426. /*ratio between frequencies of MIDI note values*/
  5427. #define twelfthRootTwo                                        1.05946309434
  5428. /*standard sampling rates*/
  5429. #define rate44khz                                    0xAC440000                    /*44100.00000 in fixed-point*/
  5430. #define rate22khz                                    0x56EE8BA3                    /*22254.54545 in fixed-point*/
  5431. #define rate22050hz                                    0x56220000                    /*22050.00000 in fixed-point*/
  5432. #define rate11khz                                    0x2B7745D1                    /*11127.27273 in fixed-point*/
  5433. #define rate11025hz                                    0x2B110000                    /*11025.00000 in fixed-point*/
  5434. /*constant for synth parameter of SndNewChannel*/
  5435. enum {
  5436.     kUseOptionalOutputDevice                                        = -1
  5437. };
  5438. /*volumes*/
  5439. enum {
  5440.     kFullVolume                                        = 0x0100,
  5441.     kNoVolume                                        = 0
  5442. };
  5443. /*development stages*/
  5444. enum {
  5445.     developStage                            = 0x20,                    /*prealpha release*/
  5446.     alphaStage                            = 0x40,                    /*alpha release*/
  5447.     betaStage                            = 0x60,                    /*beta release*/
  5448.     finalStage                            = 0x80                    /*final release*/
  5449. };
  5450. /*sizes of data buffers*/
  5451. enum {
  5452.     stateBlockSize                            = 64,                    /*size of state block buffer*/
  5453.     leftOverBlockSize                            = 32                    /*size of leftover block buffer*/
  5454. };
  5455. Data Types
  5456.  
  5457. Unsigned Fixed-Point Numbers
  5458. typedef unsigned long UnsignedFixed;                                                    /*unsigned fixed-point number*/
  5459. Times
  5460. typedef long Time;                                                    /*in half-milliseconds*/
  5461. Sound Command Record
  5462. struct SndCommand {
  5463.     unsigned short                            cmd;                    /*command number*/
  5464.     short                            param1;                    /*first parameter*/
  5465.     long                            param2;                    /*second parameter*/
  5466. };
  5467. typedef struct SndCommand SndCommand;
  5468. Audio Selection Record
  5469. struct AudioSelection {
  5470.     long                            unitType;                    /*type of time unit*/
  5471.     Fixed                            selStart;                    /*starting point of selection*/
  5472.     Fixed                            selEnd;                    /*ending point of selection/*
  5473. };
  5474. typedef struct AudioSelection AudioSelection;
  5475. typedef AudioSelection *AudioSelectionPtr;
  5476. Sound Channel Status Record
  5477. struct SCStatus {
  5478.     Fixed                            scStartTime;                    /*starting time for play from disk*/
  5479.     Fixed                            scEndTime;                    /*ending time for play from disk*/
  5480.     Fixed                            scCurrentTime;                    /*current time for play from disk*/
  5481.     Boolean                            scChannelBusy;                    /*TRUE if channel is processing cmds*/
  5482.     Boolean                            scChannelDisposed;
  5483.                                                     /*reserved*/
  5484.     Boolean                            scChannelPaused;
  5485.                                                     /*TRUE if play from disk is paused*/
  5486.     Boolean                            scUnused;                    /*unused*/
  5487.     unsigned long                            scChannelAttributes;
  5488.                                                     /*attributes of this channel*/
  5489.     long                            scCPULoad;                    /*CPU load for this channel*/
  5490. };
  5491. typedef struct SCStatus SCStatus;
  5492. typedef SCStatus *SCStatusPtr;
  5493. Sound Manager Status Record
  5494. struct SMStatus {
  5495.     short                            smMaxCPULoad;                    /*maximum load on all channels*/
  5496.     short                            smNumChannels;                    /*number of allocated channels*/
  5497.     short                            smCurCPULoad;                    /*current load on all channels*/
  5498. };
  5499. typedef struct SMStatus SMStatus;
  5500. typedef SMStatus *SMStatusPtr;
  5501. Sound Channel Record
  5502. struct SndChannel {
  5503.     struct SndChannel                            *nextChan;                    /*pointer to next channel*/
  5504.     Ptr                            firstMod;                    /*used internally*/
  5505.     SndCallBackProcPtr                            callBack;                    /*pointer to callback procedure*/
  5506.     long                            userInfo;                    /*free for application's use*/
  5507.     long                            wait;                    /*used internally*/
  5508.     SndCommand                            cmdInProgress;                    /*used internally*/
  5509.     short                            flags;                    /*used internally*/
  5510.     short                            qLength;                    /*used internally*/
  5511.     short                            qHead;                    /*used internally*/
  5512.     short                            qTail;                    /*used internally*/
  5513.     SndCommand                            queue[stdQLength];
  5514. };
  5515. typedef struct SndChannel SndChannel;
  5516. typedef SndChannel *SndChannelPtr;
  5517. Sound Header Record
  5518. struct SoundHeader {
  5519.     Ptr                            samplePtr;                    /*if NIL, samples in sampleArea*/
  5520.     unsigned long                            length;                    /*number of samples in array*/
  5521.     Fixed                            sampleRate;                    /*sample rate for this sound*/
  5522.     unsigned long                            loopStart;                    /*loop point beginning*/
  5523.     unsigned long                            loopEnd;                    /*loop point ending*/
  5524.     unsigned char                            encode;                    /*sample's encoding option*/
  5525.     unsigned char                            baseFrequency;                    /*base frequency of sample*/
  5526.     unsigned char                            sampleArea[1];
  5527. };
  5528. typedef struct SoundHeader SoundHeader;
  5529. typedef SoundHeader *SoundHeaderPtr;
  5530. Extended Sound Header Record
  5531. struct ExtSoundHeader {
  5532.     Ptr                            samplePtr;                    /*if NIL, samples in sampleArea*/
  5533.     unsigned long                            numChannels;                    /*number of channels in sample*/
  5534.     Fixed                            sampleRate;                    /*rate of original sample*/
  5535.     unsigned long                            loopStart;                    /*loop point beginning*/
  5536.     unsigned long                            loopEnd;                    /*loop point ending*/
  5537.     unsigned char                            encode;                    /*sample's encoding option*/
  5538.     unsigned char                            baseFrequency;                    /*base frequency of sample*/
  5539.     unsigned long                            numFrames;                    /*total number of frames*/
  5540.     extended80                            AIFFSampleRate;                    /*rate of original sample*/
  5541.     Ptr                            markerChunk;                    /*reserved*/
  5542.     Ptr                            instrumentChunks;
  5543.                                                     /*pointer to instrument info*/
  5544.     Ptr                            AESRecording;                    /*pointer to audio info*/
  5545.     unsigned short                            sampleSize;                    /*number of bits per sample*/
  5546.     unsigned short                            futureUse1;                    /*reserved*/
  5547.     unsigned long                            futureUse2;                    /*reserved*/
  5548.     unsigned long                            futureUse3;                    /*reserved*/
  5549.     unsigned long                            futureUse4;                    /*reserved*/
  5550.     unsigned char                            sampleArea[1];
  5551. };
  5552. typedef struct ExtSoundHeader ExtSoundHeader;
  5553. typedef ExtSoundHeader *ExtSoundHeaderPtr;
  5554. Compressed Sound Header Record
  5555. struct CmpSoundHeader {
  5556.     Ptr                            samplePtr;                    /*if NIL, samples in sampleArea*/
  5557.     unsigned long                            numChannels;                    /*number of channels in sample*/
  5558.     Fixed                            sampleRate;                    /*rate of original sample*/
  5559.     unsigned long                            loopStart;                    /*loop point beginning*/
  5560.     unsigned long                            loopEnd;                    /*loop point ending*/
  5561.     unsigned char                            encode;                    /*sample's encoding option*/
  5562.     unsigned char                            baseFrequency;                    /*base frequency of original sample*/
  5563.     unsigned long                            numFrames;                    /*length of sample in frames*/
  5564.     extended80                            AIFFSampleRate;                    /*rate of original sample*/
  5565.     Ptr                            markerChunk;                    /*reserved*/
  5566.     OSType                            format;                    /*data format type*/
  5567.     unsigned long                            futureUse2;                    /*reserved*/
  5568.     StateBlockPtr                            stateVars;                    /*pointer to StateBlock*/
  5569.     LeftOverBlockPtr                            leftOverSamples;
  5570.                                                     /*pointer to LeftOverBlock*/
  5571.     unsigned short                            compressionID;                    /*ID of compression algorithm*/
  5572.     unsigned short                            packetSize;                    /*number of bits per packet*/
  5573.     unsigned short                            snthID;                    /*unused*/
  5574.     unsigned short                            sampleSize;                    /*bits in each sample point*/
  5575.     unsigned char                            sampleArea[1];
  5576. };
  5577. typedef struct CmpSoundHeader CmpSoundHeader;
  5578. typedef CmpSoundHeader *CmpSoundHeaderPtr;
  5579. Sound Double Buffer Header Record
  5580. struct SndDoubleBufferHeader {
  5581.     short                            dbhNumChannels;                    /*number of sound channels*/
  5582.     short                            dbhSampleSize;                    /*sample size, if noncompressed*/
  5583.     short                            dbhCompressionID;
  5584.                                                     /*ID of compression algorithm*/
  5585.     short                            dbhPacketSize;                    /*number of bits per packet*/
  5586.     Fixed                            dbhSampleRate;                    /*sample rate*/
  5587.     SndDoubleBufferPtr                            dbhBufferPtr[2];
  5588.                                                     /*pointers to SndDoubleBuffer*/
  5589.     SndDoubleBackProcPtr                            dbhDoubleBack;                    /*pointer to doubleback procedure*/
  5590. };
  5591. typedef struct SndDoubleBufferHeader SndDoubleBufferHeader;
  5592. typedef SndDoubleBufferHeader *SndDoubleBufferHeaderPtr;
  5593. struct SndDoubleBufferHeader2 {
  5594.     short                            dbhNumChannels;                    /*number of sound channels*/
  5595.     short                            dbhSampleSize;                    /*sample size, if noncompressed*/
  5596.     short                            dbhCompressionID;
  5597.                                                     /*ID of compression algorithm*/
  5598.     short                            dbhPacketSize;                    /*number of bits per packet*/
  5599.     Fixed                            dbhSampleRate;                    /*sample rate*/
  5600.     SndDoubleBufferPtr                            dbhBufferPtr[2];
  5601.                                                     /*pointers to SndDoubleBuffer*/
  5602.     SndDoubleBackProcPtr                            dbhDoubleBack;                    /*pointer to doubleback procedure*/
  5603.     OSType                            dbhFormat;                    /*signature of codec*/
  5604. };
  5605. typedef struct SndDoubleBufferHeader2 SndDoubleBufferHeader2;
  5606. typedef SndDoubleBufferHeader2 *SndDoubleBufferHeaderPtr2;
  5607. Sound Double Buffer Record
  5608. struct SndDoubleBuffer {
  5609.     long                            dbNumFrames;                    /*number of frames in buffer*/
  5610.     long                            dbFlags;                    /*buffer status flags*/
  5611.     long                            dbUserInfo[2];                    /*for application's use*/
  5612.     char                            dbSoundData[1];                    /*array of data*/
  5613. };
  5614. typedef struct SndDoubleBuffer SndDoubleBuffer;
  5615. typedef SndDoubleBuffer *SndDoubleBufferPtr;
  5616. Chunk Headers
  5617. typedef unsigned long ID;                                                    /*chunk ID type*/
  5618.  
  5619. struct ChunkHeader {
  5620.     ID                            ckID;                    /*chunk type ID*/
  5621.     long                            ckSize;                    /*number of bytes of data*/
  5622. };
  5623. typedef struct ChunkHeader ChunkHeader;
  5624. Form Chunk
  5625. struct ContainerChunk {
  5626.     ID                            ckID;                    /*'FORM'*/
  5627.     long                            ckSize;                    /*number of bytes of data*/
  5628.     ID                            formType;                    /*type of file*/
  5629. };
  5630. typedef struct ContainerChunk ContainerChunk;
  5631. Format Version Chunk
  5632. struct FormatVersionChunk {
  5633.     ID                            ckID;                    /*'FVER'*/
  5634.     long                            ckSize;                    /*4 bytes*/
  5635.     unsigned long                            timestamp;                    /*date of format version*/
  5636. };
  5637. typedef struct FormatVersionChunk FormatVersionChunk;
  5638. Common Chunk
  5639. struct CommonChunk {
  5640.     ID                            ckID;                    /*'COMM'*/
  5641.     long                            ckSize;                    /*18 bytes*/
  5642.     short                            numChannels;                    /*number of channels*/
  5643.     unsigned long                            numSampleFrames;
  5644.                                                     /*number of sample frames*/
  5645.     short                            sampleSize;                    /*number of bits per sample*/
  5646.     extended80                            sampleRate;                    /*number of frames per second*/
  5647. };
  5648.  
  5649. typedef struct CommonChunk CommonChunk;
  5650. Extended Common Chunk
  5651. struct ExtCommonChunk {
  5652.     ID                            ckID;                    /*'COMM'*/
  5653.     long                            ckSize;                    /*22 bytes + compression name*/
  5654.     short                            numChannels;                    /*number of channels*/
  5655.     unsigned long                            numSampleFrames;                        
  5656.                                                     /*number of sample frames*/
  5657.     short                            sampleSize;                    /*number of bits per sample*/
  5658.     extended80                            sampleRate;                    /*number of frames per second*/
  5659.     ID                            compressionType;                        
  5660.                                                     /*compression type ID*/
  5661.     char                            compressionName[1];
  5662.                                                     /*compression type name*/
  5663. };
  5664. typedef struct ExtCommonChunk ExtCommonChunk;
  5665. Sound Data Chunk
  5666. struct SoundDataChunk {
  5667.     ID                            ckID;                    /*'SSND'*/
  5668.     long                            ckSize;                    /*size of chunk data*/
  5669.     unsigned long                            offset;                    /*offset to sound data*/
  5670.     unsigned long                            blockSize;                    /*size of alignment blocks*/
  5671. };
  5672. typedef struct SoundDataChunk SoundDataChunk;
  5673. Version Record
  5674. struct NumVersion {
  5675.     unsigned char                            majorRev;                    /*major revision level in BCD*/
  5676.     unsigned char                            minorAndBugRev;                    /*minor revision level*/
  5677.     unsigned char                            stage;                    /*development stage*/
  5678.     unsigned char                            nonRelRev;                    /*nonreleased version revision level*/
  5679. };
  5680. typedef struct NumVersion NumVersion;
  5681. Leftover Block
  5682. struct LeftOverBlock {
  5683.     unsigned long                            count;
  5684.     char                            sampleArea[leftOverBlockSize];
  5685. };
  5686. typedef struct LeftOverBlock LeftOverBlock;
  5687. typedef LeftOverBlock *LeftOverBlockPtr;
  5688. State Block
  5689. struct StateBlock {
  5690.     short                            stateVar[stateBlockSize];
  5691. };
  5692. typedef struct StateBlock StateBlock;
  5693. typedef StateBlock *StateBlockPtr;
  5694. Procedure Types
  5695. typedef pascal void (*FilePlayCompletionProcPtr)
  5696. (SndChannelPtr chan);
  5697. typedef pascal void (*SndCallBackProcPtr)
  5698. (SndChannelPtr chan, SndCommand *cmd);
  5699. typedef pascal void (*SndDoubleBackProcPtr)
  5700. (SndChannelPtr chan,           SndDoubleBufferPtr doubleBufferPtr);
  5701. Sound Manager Routines
  5702.  
  5703. Playing Sound Resources
  5704. pascal void SysBeep    (short duration);
  5705. pascal OSErr SndPlay    (SndChannelPtr chan, Handle sndHdl, 
  5706. Boolean async);
  5707. Playing From Disk
  5708. pascal OSErr SndStartFilePlay
  5709. (SndChannelPtr chan, short fRefNum,
  5710. short resNum, long bufferSize, void *theBuffer,
  5711. AudioSelectionPtr theSelection,
  5712. FilePlayCompletionProcPtr theCompletion, Boolean async);
  5713. pascal OSErr SndPauseFilePlay
  5714. (SndChannelPtr chan);
  5715. pascal OSErr SndStopFilePlay
  5716. (SndChannelPtr chan, Boolean quietNow);
  5717. Allocating and Releasing Sound Channels
  5718. pascal OSErr SndNewChannel    (SndChannelPtr *chan, short synth, long init,
  5719. SndCallBackProcPtr userRoutine);
  5720. pascal OSErr SndDisposeChannel
  5721. (SndChannelPtr chan, Boolean quietNow);
  5722. Sending Commands to a Sound Channel
  5723. pascal OSErr SndDoCommand    (SndChannelPtr chan, const SndCommand *cmd,
  5724. Boolean noWait);
  5725. pascal OSErr SndDoImmediate
  5726. (SndChannelPtr chan, const SndCommand *cmd);
  5727. Obtaining Information
  5728. pascal NumVersion SndSoundManagerVersion
  5729. (void);
  5730. pascal NumVersion MACEVersion
  5731. (void);
  5732. pascal OSErr SndControl    (short id, SndCommand *cmd);
  5733. pascal OSErr SndChannelStatus
  5734. (SndChannelPtr chan, short theLength,
  5735. SCStatusPtr theStatus);
  5736. pascal OSErr SndManagerStatus
  5737. (short theLength, SMStatusPtr theStatus);
  5738. pascal void SndGetSysBeepState
  5739. (short *sysBeepState);
  5740. pascal OSErr SndSetSysBeepState
  5741. (short sysBeepState);
  5742. pascal OSErr GetSoundHeaderOffset
  5743. (Handle sndHandle, long *offset);
  5744. Controlling Volume Levels
  5745. pascal OSErr GetSysBeepVolume
  5746. (long *level);
  5747. pascal OSErr SetSysBeepVolume
  5748. (long level);
  5749. pascal OSErr GetDefaultOutputVolume
  5750. (long *level);
  5751. pascal OSErr SetDefaultOutputVolume
  5752. (long level);
  5753. Compressing and Expanding Audio Data
  5754. pascal void Comp3to1    (const void *inBuffer, void *outBuffer, 
  5755. unsigned long cnt, const void *inState, 
  5756. void *outState, unsigned long numChannels, 
  5757. unsigned long whichChannel);
  5758. pascal void Comp6to1    (const void *inBuffer, void *outBuffer, 
  5759. unsigned long cnt, const void *inState, 
  5760. void *outState, unsigned long numChannels, 
  5761. unsigned long whichChannel);
  5762. pascal void Exp1to3    (const void *inBuffer, void *outBuffer, 
  5763. unsigned long cnt, const void *inState, 
  5764. void *outState, unsigned long numChannels, 
  5765. unsigned long whichChannel);
  5766. pascal void Exp1to6    (const void *inBuffer, void *outBuffer, 
  5767. unsigned long cnt, const void *inState, 
  5768. void *outState, unsigned long numChannels, 
  5769. unsigned long whichChannel);
  5770. Managing Double Buffers
  5771. pascal OSErr SndPlayDoubleBuffer
  5772. (SndChannelPtr chan, 
  5773. SndDoubleBufferHeaderPtr theParams);
  5774. Performing Unsigned Fixed-Point Arithmetic
  5775. pascal UnsignedFixed UnsignedFixMulDiv
  5776. (UnsignedFixed value, UnsignedFixed multiplier, UnsignedFixed divisor);
  5777. Linking Modifiers to Sound Channels
  5778. pascal OSErr SndAddModifier
  5779. (SndChannelPtr chan, Ptr modifier, short id, long init);
  5780. Application-Defined Routines
  5781.  
  5782. pascal void MyFilePlayCompletionRoutine
  5783. (SndChannelPtr chan);
  5784. pascal void MyCallback    (SndChannelPtr chan, SndCommand *cmd);
  5785. pascal void MyDoubleBackProc
  5786. (SndChannelPtr chan, 
  5787. SndDoubleBufferPtr doubleBufferPtr);
  5788. Assembly-Language Summary
  5789.  
  5790. Data Structures
  5791.  
  5792. SndCommand Data Structure0    cmd    word    command number    
  5793. 2    param1    word    first parameter    
  5794. 4    param2    long    second parameter    
  5795.  
  5796. AudioSelection Data Structure
  5797. 0    unitType    long    type of time unit    
  5798. 4    selStart    4 bytes    starting point of selection (Fixed)    
  5799. 8    selEnd    4 bytes    ending point of selection (Fixed)    
  5800.  
  5801. SCStatus Data Structure
  5802. 0    scStartTime    4 bytes    starting time for play from disk (Fixed)    
  5803. 4    scEndTime    4 bytes    ending time for play from disk (Fixed)    
  5804. 8    scCurrentTime    4 bytes    current time for play from disk (Fixed)    
  5805. 12    scChannelBusy    byte    channel playing sampled sound flag    
  5806. 13    scChannelDisposed    byte    reserved    
  5807. 14    scChannelPaused    byte    play from disk is paused flag    
  5808. 15    scUnused    byte    unused    
  5809. 16    scChannelAttributes    long    attributes of channel    
  5810. 20    scCPULoad    long    CPU load for channel    
  5811.  
  5812. SMStatus Data Structure0    smMaxCPULoad    word    maximum load on all channels    
  5813. 2    smNumChannels    word    number of allocated channels    
  5814. 4    smCurCPULoad    word    current load on all channels    
  5815.  
  5816. SndChannel Data Structure0    nextChan    long    pointer to next channel    
  5817. 4    firstMod    long    used internally    
  5818. 8    callBack    long    pointer to callback procedure    
  5819. 12    userInfo    long    free for application’s use    
  5820. 16    wait    long    used internally    
  5821. 20    cmdInProgress    8 bytes    used internally    
  5822. 28    flags    word    used internally    
  5823. 30    qLength    word    used internally    
  5824. 32    qHead    word    used internally    
  5825. 34    qTail    word    used internally    
  5826. 36    queue    variable    queue of sound commands    
  5827.  
  5828. SoundHeader Data Structure0    samplePtr    long    pointer to samples (or NIL if samples follow data structure)    
  5829. 4    length    long    number of samples in array    
  5830. 8    sampleRate    4 bytes    sample rate (Fixed)    
  5831. 12    loopStart    long    loop point beginning    
  5832. 16    loopEnd    long    loop point ending    
  5833. 20    encode    byte    sample’s encoding option    
  5834. 21    baseFrequency    byte    base frequency of sample    
  5835. 22    sampleArea    variable    sampled-sound data    
  5836.  
  5837. ExtSoundHeader Data Structure0    samplePtr    long    pointer to samples (or NIL if samples follow data structure)    
  5838. 4    numChannels    long    number of channels in sample    
  5839. 8    sampleRate    4 bytes    sample rate (Fixed)    
  5840. 12    loopStart    long    loop point beginning    
  5841. 16    loopEnd    long    loop point ending    
  5842. 20    encode    byte    sample’s encoding option    
  5843. 21    baseFrequency    byte    base frequency of sample    
  5844. 22    numFrames    long    total number of frames    
  5845. 26    AIFFSampleRate    10 bytes    rate of original sample (Extended80)    
  5846. 36    markerChunk    long    reserved    
  5847. 40    instrumentChunks    long    pointer to instrument info    
  5848. 44    AESRecording    long    pointer to audio info    
  5849. 48    sampleSize    word    number of bits per sample    
  5850. 50    futureUse1    word    reserved    
  5851. 52    futureUse2    long    reserved    
  5852. 56    futureUse3    long    reserved    
  5853. 60    futureUse4    long    reserved    
  5854. 64    sampleArea    variable    sampled-sound data    
  5855.  
  5856. CmpSoundHeader Data Structure0    samplePtr    long    pointer to samples (or NIL if samples follow data structure)    
  5857. 4    numChannels    long    number of channels in sample    
  5858. 8    sampleRate    4 bytes    sample rate (Fixed)    
  5859. 12    loopStart    long    loop point beginning    
  5860. 16    loopEnd    long    loop point ending    
  5861. 20    encode    byte    sample’s encoding option    
  5862. 21    baseFrequency    byte    base frequency of original sample    
  5863. 22    numFrames    long    length of sample in frames    
  5864. 26    AIFFSampleRate    10 bytes    rate of original sample (Extended80)    
  5865. 36    markerChunk    long    reserved    
  5866. 40    format    OSType    data format type    
  5867. 44    futureUse2    long    reserved    
  5868. 48    stateVars    long    pointer to StateBlock    
  5869. 52    leftOverSamples    long    pointer to LeftOverBlock    
  5870. 56    compressionID    word    ID of compression algorithm    
  5871. 58    packetSize    word    number of bits per packet    
  5872. 60    snthID    word    unused    
  5873. 62    sampleSize    word    bits in each sample point    
  5874. 64    sampleArea    variable    compressed sound data    
  5875.  
  5876. SndDoubleBufferHeader Data Structure0    dbhNumChannels    word    number of sound channels    
  5877. 2    dbhSampleSize    word    sample size, if noncompressed    
  5878. 4    dbhCompressionID    word    ID of compression algorithm    
  5879. 6    dbhPacketSize    word    number of bits per packet    
  5880. 8    dbhSampleRate    4 bytes    sample rate (Fixed)    
  5881. 12    dbhBufferPtr    2 longs    pointers to SndDoubleBuffer data structures    
  5882. 20    dbhDoubleBack    long    pointer to doubleback procedure    
  5883.  
  5884. SndDoubleBuffer Data Structure0    dbNumFrames    long    number of frames in buffer    
  5885. 4    dbFlags    long    buffer status flags    
  5886. 8    dbUserInfo    2 longs    for application’s use    
  5887. 16    dbSoundData    variable    array of data    
  5888.  
  5889. ChunkHeader Data Structure
  5890. 0    ckID    long    chunk type ID    
  5891. 4    ckSize    long    number of bytes of data    
  5892.  
  5893. ContainerChunk Data Structure
  5894. 0    ckID    long    chunk type ID ('FORM')    
  5895. 4    ckSize    long    number of bytes of data    
  5896. 8    formType    long    type of file    
  5897.  
  5898. FormatVersionChunk Data Structure0    ckID    long    chunk type ID ('FVER')    
  5899. 4    ckSize    long    number of bytes of data (4)    
  5900. 8    timestamp    long    date of format version    
  5901.  
  5902. CommonChunk Data Structure0    ckID    long    chunk type ID ('COMM')    
  5903. 4    ckSize    long    number of bytes of data (18)    
  5904. 8    numChannels    word    number of channels    
  5905. 10    numSampleFrames    long    number of sample frames    
  5906. 14    sampleSize    word    number of bits per sample    
  5907. 16    sampleRate    10 bytes    number of frames per second (Extended80)    
  5908.  
  5909. ExtCommonChunk Data Structure0    ckID    long    chunk type ID ('COMM')    
  5910. 4    ckSize    long    number of bytes of data (22 + length of compression name)    
  5911. 8    numChannels    word    number of channels    
  5912. 10    numSampleFrames    long    number of sample frames    
  5913. 14    sampleSize    word    number of bits per sample    
  5914. 16    sampleRate    10 bytes    number of frames per second (Extended80)    
  5915. 26    compressionType    long    compression type ID    
  5916. 30    compressionName    variable    compression type name    
  5917.  
  5918. SoundDataChunk0    ckID    long    chunk type ID ('SSND')    
  5919. 4    ckSize    long    number of bytes of data    
  5920. 8    offset    long    offset to sound data    
  5921. 12    blockSize    long    size of alignment blocks    
  5922.  
  5923. Trap Macros
  5924.  
  5925. Trap Macro Requiring Routine Selectors
  5926. _SoundDispatch
  5927. Selector    Routine    
  5928. $00000010    MACEVersion    
  5929. $00040010    Comp3to1    
  5930. $00080010    Exp1to3    
  5931. $000C0008    SndSoundManagerVersion    
  5932. $000C0010    Comp6to1    
  5933. $00100008    SndChannelStatus    
  5934. $00100010    Exp1to6    
  5935. $00140008    SndManagerStatus    
  5936. $00180008    SndGetSysBeepState    
  5937. $001C0008    SndSetSysBeepState    
  5938. $00200008    SndPlayDoubleBuffer    
  5939. $02040008    SndPauseFilePlay    
  5940. $02240024    GetSysBeepVolume    
  5941. $02280024    SetSysBeepVolume    
  5942. $022C0024    GetDefaultOutputVolume    
  5943. $02300024    SetDefaultOutputVolume    
  5944. $03080008    SndStopFilePlay    
  5945. $0D000008    SndStartFilePlay    
  5946. $04040024    GetSoundHeaderOffset    
  5947.  
  5948. Result CodesnoErr    0    No error    
  5949. paramErr    –50    A parameter is incorrect    
  5950. noHardwareErr    –200    Required sound hardware not available    
  5951. notEnoughHardwareErr    –201    Insufficient hardware available    
  5952. queueFull    –203    No room in the queue    
  5953. resProblem    –204    Problem loading the resource    
  5954. badChannel    –205    Channel is corrupt or unusable    
  5955. badFormat    –206    Resource is corrupt or unusable    
  5956. notEnoughBufferSpace    –207    Insufficient memory available    
  5957. badFileFormat    –208    File is corrupt or unusable, or not AIFF or AIFF-C    
  5958. channelBusy    –209    Channel is busy    
  5959. buffersTooSmall    –210    Buffer is too small    
  5960. channelNotBusy    –211    Channel not currently used    
  5961. noMoreRealTime    –212    Not enough CPU time available    
  5962. siInvalidCompression    –223    Invalid compression type    
  5963.  
  5964.  
  5965.  
  5966. Listing 3-0
  5967. Table 3-0
  5968. Sound Input Manager
  5969. Contents
  5970. About the Sound Input Manager3-3
  5971. Sound Recording Without the Standard Interface3-4
  5972. Interaction With Sound Input Devices3-4
  5973. Sound Input Device Drivers3-5
  5974. Using the Sound Input Manager3-5
  5975. Recording Sounds Directly From a Device3-6
  5976. Defining a Sound Input Completion Routine3-9
  5977. Defining a Sound Input Interrupt Routine3-10
  5978. Getting and Setting Sound Input Device Information3-10
  5979. Writing a Sound Input Device Driver3-13
  5980. Responding to Status and Control Requests3-13
  5981. Responding to Read Requests3-15
  5982. Supporting Stereo Recording3-16
  5983. Supporting Continuous Recording3-17
  5984. Sound Input Manager Reference3-17
  5985. Constants3-17
  5986. Gestalt Selector and Response Bits3-17
  5987. Sound Input Device Information Selectors3-18
  5988. Data Structures3-26
  5989. Sound Input Parameter Blocks3-26
  5990. Sound Input Manager Routines3-27
  5991. Recording Sounds3-28
  5992. Opening and Closing Sound Input Devices3-31
  5993. Recording Sounds Directly From Sound Input Devices3-33
  5994. Manipulating Device Settings3-41
  5995. Constructing Sound Resource and File Headers3-44
  5996. Registering Sound Input Devices3-48
  5997. Converting Between Milliseconds and Bytes3-51
  5998. Obtaining Information3-53
  5999. Application-Defined Routines3-53
  6000. Sound Input Completion Routines3-54
  6001. Sound Input Interrupt Routines3-55
  6002. Summary of the Sound Input Manager3-57
  6003. Pascal Summary3-57
  6004. Constants3-57
  6005. Data Types3-58
  6006. Sound Input Manager Routines3-59
  6007. Application-Defined Routines3-60
  6008. C Summary3-61
  6009. Constants3-61
  6010. Data Types3-62
  6011. Sound Input Manager Routines3-63
  6012. Application-Defined Routines3-65
  6013. Assembly-Language Summary3-65
  6014. Data Structures3-65
  6015. Trap Macros3-66
  6016. Result Codes3-66
  6017. Sound Input Manager
  6018. This chapter describes the Sound Input Manager, the part of the Macintosh system software that controls the recording of sound through sound input devices. You can use the Sound Input Manager to display and manage the sound recording dialog box. This ensures that the user is presented with a consistent and standard user interface for sound recording. You can, however, also use Sound Input Manager routines to record sound without the sound recording dialog box or to interact directly with a sound input device driver.
  6019. To use this chapter, you should already be familiar with the information in the chapter “Introduction to Sound on the Macintosh” earlier in this book, and in particular with the portions of that chapter that concern sound recording. That chapter explains how your application can record either a sound resource or a sound file using the standard sound recording dialog box. You need to read this chapter only if you need to interact with the Sound Input Manager at a lower level than is allowed by the high-level functions SndRecord and SndRecordToFile. For example, you need to read this chapter to learn how to
  6020. n    record sound without using the sound recording dialog box
  6021. n    interact with a sound input device driver
  6022. n    write a sound input device driver
  6023. To use this chapter, you should also be familiar with the chapter “Sound Manager” in this book, especially the portions of that chapter that describe
  6024. n    the format of sampled-sound data
  6025. n    the Macintosh Audio Compression and Expansion (MACE) routines
  6026. n    the structure of sound resources and sound files
  6027. n    the use of the Gestalt function to determine whether certain sound-related facilities are available.
  6028. If you are writing a sound input device driver, you should already be familiar with writing device drivers in general, as described in the book Inside Macintosh: Devices.
  6029.  
  6030. About the Sound Input Manager
  6031.  
  6032. The Sound Input Manager uses sound input device drivers to allow applications to access sound input hardware in a device-independent way. A sound input device driver is a standard Macintosh device driver used to interface to an audio digitizer or other recording hardware. If you use the Sound Input Manager’s high-level routines, the Sound Input Manager handles all communication with a sound input device driver for you. If, however, you need to use the Sound Input Manager’s low-level routines, you must open a sound input device driver yourself. You might also need to get information about certain attributes of a sound input device. Sound input device drivers allow your application to query a device about such attributes.
  6033. Sound Recording Without the Standard Interface
  6034.  
  6035. The Sound Input Manager provides your application with the ability to record and digitally store sounds in a device-independent manner even if your application does not use the standard sound recording interface. In cases where you need very fine control over the recording process, you can call various low-level sound input routines.
  6036. Your application can obtain control over sound recording in two different ways. First, if your application uses the sound recording dialog box, you can modify the dialog box’s features by defining a custom filter procedure, as explained in detail in the chapter “Dialog Manager” in Inside Macintosh: Macintosh Toolbox Essentials. Second, if your application needs to fine tune the sound recording process itself (or if your application does not use the standard sound recording dialog box), then the application must use the Sound Input Manager’s low-level routines.
  6037. In instances where you need to gain greater control over the recording process, you can use a set of routines that manipulate the incoming sound data by using sound parameter blocks. The parameter blocks contain information about the current recording device, the length recorded, a routine to call on completion of the recording, and so forth. You can call the SPBRecord function (or the SPBRecordToFile function) to begin a recording. Then you can use the functions SPBPauseRecording, SPBResumeRecording, and SPBStopRecording to control the recording. Note that you need to open a device (using the SPBOpenDevice function) before you can record from it. On completion of the recording, you should close the device (using the SPBCloseDevice function).
  6038. If you do record sounds using the Sound Input Manager’s low-level routines, you also need to set up your own sound resource headers or sound files, because the Sound Input Manager’s low-level routines return raw sampled-sound data to your application. The Sound Input Manager provides two functions, SetupSndHeader and SetupAIFFHeader, that allow you to set up your own sound resource headers or sound files.
  6039. Interaction With Sound Input Devices
  6040.  
  6041. The Sound Input Manager provides routines that allow your application to request information about a sound input device or to change a sound input device’s settings. The types of information you can obtain about a sound input device include
  6042. n    the name, icon, and icon mask of the device driver
  6043. n    whether the device driver supports asynchronous recording
  6044. n    the device’s settings, such as the number of channels the device is to record, the compression type, the number of bytes per sample at the current compression setting, and the sample rate to be produced by the device
  6045. n    the range of compression types, sample rates, and sample sizes that the device supports
  6046. You can also use the Sound Input Manager to change some of a sound input device’s settings and to turn features on and off. For example, you can turn on and off automatic gain control on some device drivers. Automatic gain control moderates sound recording to give a consistent signal level. Second, you can turn on and off the playthrough feature, which allows the user to hear through the Macintosh speaker the sound being recorded. Third, you can turn on and off VOX recording, or voice-activated recording, which allows your application to record only when the amplitude of sound input exceeds a certain level. You can use VOX recording either to prevent recording from starting until sound is at least a certain amplitude or to automatically stop recording when sound falls below a certain amplitude. This latter capability is called VOX stopping.
  6047. An important feature of sound input devices is continuous recording. All sound input devices that support asynchronous recording should support continuous recording as well. Continuous recording allows your application to make several consecutive calls to the SPBRecord function without losing data between calls. For example, you might need to record a lengthy sound to disk but not be able to fit the entire sound into RAM. Thus, it’s important to be able to save a buffer of data to disk while the sound input device driver continues to collect recorded data. The Sound Input Manager’s SndRecordToFile function relies on continuous recording.
  6048. To get information about a device or to turn features on and off, you can use the SPBGetDeviceInfo and SPBSetDeviceInfo functions. These functions allow you to use sound input device information selectors to specify what type of information you need to know about the device or what settings you wish to change.
  6049. Sound Input Device Drivers
  6050.  
  6051. The Sound Input Manager also provides several routines intended for use only by sound input device drivers. Sound input device drivers need to register themselves with the Sound Input Manager by calling the SPBSignInDevice function. This makes that device visible in the Sound In control panel for possible selection as the current input device. You can remove a device from that panel by calling the SPBSignOutDevice function.
  6052. For Macintosh computers with built-in sound recording hardware, the system software includes a sound input device driver. This driver automatically calls SPBSignInDevice when the computer starts up. If you are creating a sound input device driver for some other sound recording hardware, your device driver must register itself at startup time. Once your driver is registered, it must respond to Status, Control, and Read calls issued by the Sound Input Manager. The Sound Input Manager issues Status calls to get information about a device, Control calls to set device settings, and Read calls to initiate recording.
  6053.  
  6054. Using the Sound Input Manager
  6055.  
  6056. You can use the Sound Input Manager to record sounds with the sound recording dialog box, to record sounds directly from a device, to get and set information about a sound input device, and to register your sound input device driver so that it can respond to Read, Status, and Control calls. This section does not explain how to record sounds using the sound recording dialog box; for information on that, see the chapter “Introduction to Sound on the Macintosh” in this book.
  6057. Recording Sounds Directly From a Device
  6058.  
  6059. The Sound Input Manager provides a number of routines that you can use for low-level control over the recording process (such as the ability to intercept sound input data at interrupt time). You can open a sound input device and read data from it by calling these low-level Sound Input Manager routines. Several of those routines access information through a sound input parameter block, which is defined by the SPB data type:
  6060. TYPE SPB =
  6061. RECORD
  6062.     inRefNum:                            LongInt;                {reference number of input device}
  6063.     count:                            LongInt;                {number of bytes to record}
  6064.     milliseconds:                            LongInt;                {number of milliseconds to record}
  6065.     bufferLength:                            LongInt;                {length of buffer to record into}
  6066.     bufferPtr:                            Ptr;                {pointer to buffer to record into}
  6067.     completionRoutine:                            ProcPtr;                {pointer to a completion routine}
  6068.     interruptRoutine:                            ProcPtr;                {pointer to an interrupt routine}
  6069.     userLong:                            LongInt;                {for application's use}
  6070.     error:                            OSErr;                {error returned after recording}
  6071.     unused1:                            LongInt;                {reserved}
  6072. END;
  6073. The inRefNum field indicates the reference number of the sound input device from which the recording is to occur. You can obtain the reference number of the default sound input device by using the SPBOpenDevice function.
  6074. The count, milliseconds, and bufferLength fields jointly determine the length of recording. The count field indicates the number of bytes to record; the milliseconds field indicates the number of milliseconds to record; and the bufferLength field indicates the length in bytes of the buffer into which the recorded sound data is to be placed. If the count and milliseconds fields are not equivalent, then the field which specifies the longer recording time is used. If the buffer specified by the bufferLength field is shorter than this recording time, then the recording time is truncated so that the recorded data can fit into the buffer specified by the bufferPtr field. The Sound Input Manager provides two functions, SPBMilliSecondsToBytes and SPBBytesToMilliSeconds, that allow you to convert between byte and millisecond values.
  6075. After recording finishes, the count and milliseconds fields indicate the number of bytes and milliseconds actually recorded.
  6076. The completionRoutine and interruptRoutine fields allow your application to define a sound input completion routine and a sound input interrupt routine, respectively. More information on these routines is provided later in this section.
  6077. The userLong field contains a long integer that is provided for your application’s own use. You can use this field, for instance, to pass a handle to an application-defined structure to the sound input completion or interrupt routine. Or, you can use this field to store the value of your application’s A5 register, so that your sound input completion or interrupt routine can access your application’s global variables. For more information on preserving the value of the A5 register, see the discussion of the SetA5 and SetCurrentA5 functions in the chapter “Memory Management Utilities” in Inside Macintosh: Memory.
  6078. The error field describes any errors that occur during the recording. This field contains a value greater than 0 while recording unless an error occurs, in which case it contains a value less than 0 that indicates an operating system error. Your application can poll this field to check on the status of an asynchronous recording. If recording terminates without an error, this field contains 0.
  6079. Listing 3-1 shows how to set up a sound parameter block and record synchronously using the SPBRecord function. This procedure takes one parameter, a handle to a block of memory in which the recorded sound data is to be stored. It is assumed that the block of memory is large enough to hold the sound to be recorded.
  6080. Listing 3-1    Recording directly from a sound input device
  6081.  
  6082. PROCEDURE MyRecordSnd (mySndH: Handle);
  6083. CONST
  6084.     kAsync = TRUE;
  6085.     kMiddleC = 60;
  6086. VAR
  6087.     mySPB:                    SPB;                {a sound input parameter block}
  6088.     myInRefNum:                    LongInt;                {device reference number}
  6089.     myBuffSize:                    LongInt;                {size of buffer to record into}
  6090.     myHeadrLen:                    Integer;                {length of sound header}
  6091.     myNumChans:                    Integer;                {number of channels}
  6092.     mySampSize:                    Integer;                {size of a sample}
  6093.     mySampRate:                    Fixed;                {sample rate}
  6094.     myCompType:                    OSType;                {compression type}
  6095.     myErr:                    OSErr;
  6096. BEGIN
  6097.     {Open the default input device for reading and writing.}
  6098.     myErr := SPBOpenDevice('', siWritePermission, myInRefNum);
  6099.  
  6100.     IF myErr = noErr THEN
  6101.     BEGIN
  6102.         {Get current settings of sound input device.}
  6103.         MyGetDeviceSettings(myInRefNum, myNumChans, mySampRate, 
  6104.                                     mySampSize, myCompType);
  6105.  
  6106.         {Set up handle to contain the 'snd ' resource header.}
  6107.         myErr := SetupSndHeader(mySndH, myNumChans, mySampRate,mySampSize,  
  6108.                                             myCompType, kMiddleC, 0, myHeadrLen);
  6109.  
  6110.         {Leave room in buffer for the sound resource header.}
  6111.         myBuffSize := GetHandleSize(mySndH) - myHeadrLen;
  6112.  
  6113.         {Lock down the sound handle until the recording is over.}
  6114.         HLockHi(mySndH);
  6115.  
  6116.         {Set up the sound input parameter block.}
  6117.         WITH mySPB do
  6118.         BEGIN
  6119.             inRefNum := myInRefNum;                                            {input device reference number}
  6120.             count := myBuffSize;                                            {number of bytes to record}
  6121.             milliseconds := 0;                                            {no milliseconds}
  6122.             bufferLength := myBuffSize;                                            {length of buffer}
  6123.             bufferPtr := Ptr(ORD4(mySndH^) + myHeadrLen);
  6124.                                                         {put data after 'snd ' header}
  6125.             completionRoutine := NIL;                                            {no completion routine}
  6126.             interruptRoutine := NIL;                                            {no interrupt routine}
  6127.             userLong := 0;                                            {no user data}
  6128.             error := noErr;                                            {clear error field}
  6129.             unused1 := 0;                                            {clear reserved field}
  6130.         END;
  6131.  
  6132.         {Record synchronously through the open sound input device.}
  6133.         myErr := SPBRecord(@mySPB, NOT kAsync);
  6134.  
  6135.         HUnlock(mySndH);                                                {unlock the handle}
  6136.  
  6137.         {Indicate the number of bytes actually recorded.}
  6138.         myErr := SetupSndHeader(mySndH, myNumChans, mySampRate, mySampSize, 
  6139.                                             myCompType, kMiddleC, mySPB.count,
  6140.                                             myHeadrLen);
  6141.  
  6142.         {Close the input device.}
  6143.         myErr := SPBCloseDevice(myInRefNum);
  6144.     END;
  6145. END;
  6146. The MyRecordSnd procedure defined in Listing 3-1 opens the default sound input device by using the SPBOpenDevice function. You can specify one of two values for the permission parameter of SPBOpenDevice:
  6147. CONST
  6148.     siReadPermission                        = 0;        {open device for reading}
  6149.     siWritePermission                        = 1;        {open device for reading/writing}
  6150. You must open a device for both reading and writing if you intend to use the SPBSetDeviceInfo function or the SPBRecord function. If SPBOpenDevice successfully opens the specified device for reading and writing, MyRecordSnd calls the MyGetDeviceSettings procedure (defined in Listing 3-3 on page 3-12). That procedure calls the Sound Input Manager function SPBGetDeviceInfo (explained in “Getting and Setting Sound Input Device Information” on page 3-10) to determine the current number of channels, sample rate, sample size, and compression type in use by the device.
  6151. This information is then passed to the SetupSndHeader function, which sets up the handle mySndH with a sound header describing the current device settings. After doing this, MyRecordSnd sets up a sound input parameter block and calls the SPBRecord function to record a sound. Note that the handle must be locked during the recording because the parameter block contains a pointer to the input buffer. After the recording is done, MyRecordSnd once again calls the SetupSndHeader function to fill in the actual number of bytes recorded.
  6152. If the MyRecordSnd procedure defined in Listing 3-1 executes successfully, the handle mySndH points to a resource of type 'snd '. Your application can then synchronously play the recorded sound, for example, by executing the following line of code:
  6153. myErr := SndPlay(NIL, mySndH, FALSE);
  6154. For more information on playing sounds your application has recorded, see the chapter “Sound Manager” in this book.
  6155. Defining a Sound Input Completion Routine
  6156.  
  6157. The completionRoutine field of the sound parameter block record contains the address of a completion routine that is executed when the recording terminates normally, either by reaching its prescribed time or size limits or by the application calling the SPBStopRecording function. A completion routine should have the following format:
  6158. PROCEDURE MySICompletionRoutine (inParamPtr: SPBPtr);
  6159. The completion routine is passed the address of the sound input parameter block that was passed to the SPBRecord function. You can gain access to other data structures in your application by passing an address in the userLong field of the parameter block. After the completion routine executes, your application should check the error field of the sound input parameter block to see if an error code was returned.
  6160. Your sound input interrupt routine is always called at interrupt time, so it should not call routines that might allocate or move memory or assume that A5 is set up. For more information on sound input interrupt routines, see “Sound Input Interrupt Routines” beginning on page 3-55.
  6161. Defining a Sound Input Interrupt Routine
  6162.  
  6163. The interruptRoutine field of the sound input parameter block contains the address of a routine that executes when the internal buffers of an asynchronous recording device are filled. The internal buffers contain raw sound samples taken directly from the input device. The interrupt routine can modify the samples in the buffer in any way it requires. The processed samples are then written to the application buffer. If compression is enabled, the modified data is compressed after your interrupt routine operates on the samples and before the samples are written to the application buffer.
  6164. Your sound input interrupt routine is always called at interrupt time, so it should not call routines that might allocate or move memory or assume that A5 is set up. For more information on sound input interrupt routines, see “Sound Input Interrupt Routines” beginning on page 3-55. 
  6165. Getting and Setting Sound Input Device Information
  6166.  
  6167. You can get information about a specific sound input device and alter a sound input device’s settings by calling the functions SPBGetDeviceInfo and SPBSetDeviceInfo. These functions accept sound input device information selectors that determine which information you need or want to change. The selectors currently available are defined by constants of type OSType.
  6168. Here is a list of the selectors that all sound input device drivers must support. For complete details on all the selectors described in this section, see “Sound Input Device Information Selectors” beginning on page 3-18.
  6169. CONST
  6170.     siAsync                                = 'asyn';                {asynchronous capability}
  6171.     siChannelAvailable                                = 'chav';                {number of channels available}
  6172.     siCompressionAvailable                                = 'cmav';                {compression types available}
  6173.     siCompressionFactor                                = 'cmfa';                {current compression factor}
  6174.     siCompressionType                                = 'comp';                {compression type}
  6175.     siContinuous                                = 'cont';                {continuous recording}
  6176.     siDeviceBufferInfo                                = 'dbin';                {size of interrupt buffer}
  6177.     siDeviceConnected                                = 'dcon';                {input device connection status}
  6178.     siDeviceIcon                                = 'icon';                {input device icon}
  6179.     siDeviceName                                = 'name';                {input device name}
  6180.     siLevelMeterOnOff                                = 'lmet';                {level meter state}
  6181.     siNumberChannels                                = 'chan';                {current number of channels}
  6182.     siRecordingQuality                                = 'qual';                {recording quality}
  6183.     siSampleRate                                = 'srat';                {current sample rate}
  6184.     siSampleRateAvailable                                = 'srav';                {sample rates available}
  6185.     siSampleSizeAvailable                                = 'ssav';                {sample sizes available}
  6186.     siSampleSize                                = 'ssiz';                {current sample size}
  6187.     siTwosComplementOnOff                                = 'twos';                {two's complement state}
  6188. The Sound Input Manager defines several selectors that specifically help it interact with sound input device drivers. Your application should not use any of these selectors, but if you are implementing a sound input device driver, you need to support these selectors. They are:
  6189. CONST
  6190.     siCloseDriver                                = 'clos';                {release driver}
  6191.     siInitializeDriver                                = 'init';                {initialize driver}
  6192.     siPauseRecording                                = 'paus';                {pause recording}
  6193.     siUserInterruptProc                                = 'user';                {set sound input interrupt routine}
  6194. Finally, there are a number of sound input device information selectors that sound input device drivers can optionally support. If you are writing an application, you can use these selectors to interact with a sound input device driver, but you should be aware that some drivers might not support all of them. To determine if a driver supports one of these selectors, you can use the SPBGetDeviceInfo function. If no errors are returned, then the selector is supported when using the SPBGetDeviceInfo and the SPBSetDeviceInfo functions.
  6195. CONST
  6196.     siActiveChannels                                = 'chac';                {channels active}
  6197.     siActiveLevels                                = 'lmac';                {levels active}
  6198.     siAGCOnOff                                = 'agc ';                {automatic gain control state}
  6199.     siCompressionHeader                                = 'cmhd';                {get compression header}
  6200.     siCompressionNames                                = 'cnam';                {return compression type names}
  6201.     siInputGain                                = 'gain';                {input gain level}
  6202.     siInputSource                                = 'sour';                {input source selector}
  6203.     siInputSourceNames                                = 'snam';                {input source names}
  6204.     siOptionsDialog                                = 'optd';                {display options dialog box}
  6205.     siPlayThruOnOff                                = 'plth';                {play-through state}
  6206.     siStereoInputGain                                = 'sgai';                {stereo input gain level}
  6207.     siVoxRecordInfo                                = 'voxr';                {VOX record parameters}
  6208.     siVoxStopInfo                                = 'voxs';                {VOX stop parameters}
  6209. The format of the relevant data (either returned by the Sound Input Manager or provided by you) depends on the selector you provide. For example, if you want to determine the name of some sound input device, you can pass to the SPBGetDeviceInfo function the siDeviceName selector and a pointer to a 256-byte buffer. If the SPBGetDeviceInfo function can get the information, it fills that buffer with the name of the specified sound input device. Listing 3-2 illustrates one way you can determine the name of a particular sound input device.
  6210. Listing 3-2    Determining the name of a sound input device
  6211.  
  6212. FUNCTION MyGetDeviceName (myRefNum: LongInt; VAR dName: Str255): OSErr;
  6213. BEGIN
  6214.     MyGetDeviceName := SPBGetDeviceInfo(myRefNum, siDeviceName, Ptr(@dName));
  6215. END;
  6216. Note
  6217. You can get the name and icon of all connected sound input devices without using sound input information selectors by using the SPBGetIndexedDevice function, which is described on page 3-49.u
  6218. Some selectors cause the SPBGetDeviceInfo function to return data of other types. Listing 3-3 illustrates how to determine the number of channels, the sample rate, the sample size, and the compression type currently in use by a given sound input device. (The procedure defined in Listing 3-3 is called in the procedure defined in Listing 3-1.)
  6219. Listing 3-3    Determining some sound input device settings
  6220.  
  6221. PROCEDURE MyGetDeviceSettings (myRefNum: LongInt; 
  6222.                                             VAR numChannels: Integer; 
  6223.                                             VAR sampleRate: Fixed; 
  6224.                                             VAR sampleSize: Integer; 
  6225.                                             VAR compressionType: OSType);
  6226. VAR
  6227.     myErr:                OSErr;
  6228. BEGIN
  6229.     {Get number of active channels.}
  6230.     myErr := SPBGetDeviceInfo (myRefNum, siNumberChannels, Ptr(@numChannels));
  6231.     {Get sample rate.}
  6232.     myErr := SPBGetDeviceInfo(myRefNum, siSampleRate, Ptr(@sampleRate));
  6233.     {Get sample size.}
  6234.     myErr := SPBGetDeviceInfo(myRefNum, siSampleSize, Ptr(@sampleSize));
  6235.     {Get compression type.}
  6236.     myErr := SPBGetDeviceInfo(myRefNum, siCompressionType, 
  6237.                                                                     Ptr(@compressionType));
  6238. END;
  6239. All of the selectors that return a handle allocate the memory for that handle in the current heap zone; you are responsible for disposing of that handle when you are done with it, and you should verify that there is enough memory for such a handle before calling the selector.
  6240. Writing a Sound Input Device Driver
  6241.  
  6242. This section describes what you need to do when you do write a sound input device driver. If you write a sound input device driver, you should set the drvrFlags field of the sound input device driver’s header to indicate that the driver can handle Status, Control, and Read requests. The driver header should also indicate that the driver needs to be locked.
  6243. IMPORTANT
  6244. You don’t need to write a device driver to use sound input capabilities.s
  6245. After you create a device driver, you must write an extension that installs it. Before your extension installs the driver, it should pass the Gestalt function the gestaltSoundAttr attribute selector and inspect the gestaltSoundIOMgrPresent bit to determine if the sound input routines are available. If so, the extension should install the sound input device driver into the unit table just as any other driver must be installed.
  6246. After installing the driver, the extension must then make an Open request to the driver, so that the driver can perform any necessary initialization. In particular, the driver might set the dCtlStorage field of the device control entry to a pointer or a handle to a block in the system heap containing all of the variables that it might need. Finally, the device driver signs into the Sound Input Manager by calling the SPBSignInDevice function.
  6247. Once signed in, a driver can receive Status, Control, and Read requests from the Sound Input Manager. On entry, the A0 register contains a pointer to a standard Device Manager parameter block, and the A1 register contains a pointer to the device control entry. For more information on using registers in a device driver, see Inside Macintosh: Devices.
  6248. Responding to Status and Control Requests
  6249.  
  6250. The Sound Input Manager supports sound input device information selectors by sending your device driver Status and Control requests. It uses Status requests to get information about your device; it uses Control requests to change settings of your sound input device.
  6251. The behavior of your sound input device driver in response to Status and Control requests depends on the value of the csCode field of the Device Manager control parameter block. If the csCode field contains 2, then the sound input information selector is passed in the first 4 bytes of the csParam field of the Device Manager control parameter block. For Status requests, the next 18 bytes can be used for your device driver to pass information back to an application. For Control requests, these 18 bytes are used by an application to pass data to your sound input device driver.
  6252. Figure 3-1 shows the contents of the csParam field of the Device Manager control parameter block for a sample Status request. The first four bytes of the csParam field contain the input selector 'srav', which is a request for the available sample rates. The next four bytes of the field contain a pointer to an application-supplied buffer in which to return the data (the number of rates available) from the Status request.
  6253. Figure 3-1    An example of the csParam field for a Status request
  6254.  
  6255. On exit from the Status request, your sound input device driver can respond in one of two ways. If you are returning fewer than 18 bytes of data, your device driver should specify in the first 4 bytes of the csParam field of the Device Manager control parameter block the number of bytes of data being returned and place the data in the following 18 bytes. In this case, the Sound Input Manager copies the data to the application-supplied buffer identified in Figure 3-1. If you are returning more than 18 bytes of data, your device driver should copy the data to the application-supplied buffer. In this case, your device driver needs to place a zero in the first 4 bytes of the csParam field to indicate to the Sound Input Manager that the data has already been copied to the application-supplied buffer.
  6256. Figure 3-2 shows the contents of the csParam field of the Device Manager control parameter block for a sample Control request. The first four bytes of the csParam field contain the input selector 'srat' which determines the sample rate for the sound input device. The next eighteen bytes contain the data, which in this example is the sample rate to set for your sound input device. This is a Fixed value of four bytes in length.
  6257. Figure 3-2    An example of the csParam field for a Control request
  6258.  
  6259. Note
  6260. Note
  6261. Some sound input information selectors require your sound input device driver to allocate a handle in which to store information. In this case, your driver should attempt to allocate an appropriately sized handle in the current heap zone. If allocation fails, your driver should return the appropriate Memory Manager result code.u
  6262. Your sound input device driver must respond to a core set of selectors, but the remaining selectors defined by Apple are optional. Your device driver might also define private selectors to support proprietary features. (Selectors containing all lowercase letters, however, are reserved by Apple.) The section “Getting and Setting Sound Input Device Information” beginning on page 3-10 lists the core selectors and other selectors that have been defined.
  6263. If the csCode field contains 1 (which can occur only for Control requests), the Sound Input Manager is attempting to stop asynchronous recording; that is, it is issuing a KillIO request. In response to this, the driver should stop copying data to the application buffer, update the ioActCount field of the request parameter block, and return via an RTS instruction.
  6264. Before exiting after a Status and Control request, your sound input device driver should fill the D0 register with the appropriate result code or noErr. To exit, your sound input device driver should check whether the Status and Control request was executed immediately or was queued.
  6265. Note
  6266. In current versions of system software, the Sound Input Manager always issues Status and Control requests immediately. This might change in future versions of system software.u
  6267. Your sound input device driver can determine whether a request is issued immediately by checking the noQueueBit in the ioTrap field of the Device Manager control parameter block. If the request was made immediately, the Control routine should return via an RTS instruction; if the request was queued, the Control routine should jump to the Device Manager’s IODone function via the global jump vector JIODone. You need to make sure that the A0 and A1 registers are set the same as they are on entry to the device driver or JIODone will fail. 
  6268. Responding to Read Requests
  6269.  
  6270. When a sound input device receives a Read request, it must start recording and saving recorded data into the buffer specified by the ioBuffer field of the request parameter block. If that field is NIL, the driver should record but not save the data. During a Read request, your sound input device driver can access the sound parameter block that initiated recording through the ioMisc field of the request parameter block.
  6271. If a previous Control request has assigned a sound input interrupt routine to the device driver and your driver records asynchronously, then the driver must call the routine each time its internal buffer becomes filled, setting up registers as described in “Defining a Sound Input Interrupt Routine” on page 3-10. The buffer size that your device driver specifies in the D1 register should indicate how much your device records during every interrupt. For example, a sound input device driver that uses the serial port might use a buffer as small as 3 bytes. For the built-in sound input port on the Macintosh LC and other Macintosh models, the buffer is 512 bytes long.
  6272. Your device driver should update the ioActCount field of the request parameter block with the actual number of bytes of sampled-sound data recorded. This allows the Sound Input Manager to monitor the activity of your device driver. Whether your device driver operates synchronously or asynchronously, it should complete recording by jumping to the Device Manager’s IODone function via the global jump vector JIODone. You need to set the D0 register to the appropriate result code before jumping to the Device Manager’s IODone function. 
  6273. Supporting Stereo Recording
  6274.  
  6275. Many sound input devices support recording stereo sounds (that is, sounds from two or more channels). If you are writing a device driver for a stereo device, you need to make sure that you support the siNumberChannels, siActiveChannels, and siActiveLevels selectors.
  6276. The siNumberChannels selector controls the number of sound input channels and thereby determines the format of the data stream your device driver produces. If the number of channels is 1, the driver should produce monophonic data in response to a Read request. If the number of channels is 2, the driver should produce interleaved stereo data in response to a Read request.
  6277. The siActiveChannels selector controls which of the available input channels are used for recording. The active channels are specified using a bitmap value. For example, the value $01 indicates that the first channel (the left channel) is to be used. The value $02 indicates that the second channel (the right channel) is to be used.
  6278. The siNumberChannels and siActiveChannels selectors together determine the exact format of the output data stream. If the current number of channels is 1 and the current active channel bitmap is $01, the driver should produce a stream of monophonic data containing samples only from the left input channel. If the current number of channels is 1 and the current active channel bitmap is $02, the driver should produce a stream of monophonic data containing samples only from the right input channel. If the current number of channels is 1 and the current active channel bitmap is $03, the driver should mix the right and left channels to produce a stream of monophonic data. If the current number of channels is 2 and the current active channel bitmap is $03, the driver should produce a stream of interleaved samples from the left and right input channels.
  6279. Note
  6280. If the siActiveChannels selector is never passed to a sound input device driver, it’s recommended that the active channel default bitmap for both monophonic and stereo recording should be $03. When the active channel bitmap conflicts with the number of channels (for example, there are two channels but the active channel bitmap is $01), you should use the default value of $03.u
  6281. Supporting Continuous Recording
  6282.  
  6283. If your sound input device driver supports continuous recording, it must do more than respond to Status, Control, and Read requests. It must also, if continuous recording is on, begin recording into an internal ring buffer as soon as a Read request completes. The buffer should be made large enough so that the sound input device driver can support successive requests to the SPBRecord function in most circumstances; however, if your driver exhausts the internal buffer, your driver should begin recording again at the start of the buffer.
  6284. When the sound input device driver receives a subsequent Read request, it should record to the application’s buffer first all of the data in the internal ring buffer and then as much fresh data as it can record during one interrupt.
  6285. If a Read terminates due to a KillIO request, your sound input device driver does not need to continue recording samples to the internal ring buffer until after the next uninterrupted Read request.
  6286.  
  6287. Sound Input Manager Reference
  6288.  
  6289. This section describes the constants, data structure, and the routines provided by the Sound Input Manager.
  6290. Constants
  6291.  
  6292. This section describes the constants you can use with the SPBSetDeviceInfo and SPBGetDeviceInfo functions to set or get device information. It also lists the Gestalt function sound attributes selector and the returned bit numbers that are relevant to the Sound Input Manager. All other constants defined by the Sound Input Manager are described at the appropriate location in this chapter. (For example, the constants that you can use to specify sound recording qualities are described in connection with the SndRecord function beginning on page 3-28.)
  6293. Gestalt Selector and Response Bits
  6294.  
  6295. You can pass the gestaltSoundAttr selector to the Gestalt function to determine information about the sound input capabilities of a Macintosh computer.
  6296. CONST
  6297.     gestaltSoundAttr                                    = 'snd ';                {sound attributes selector}
  6298. The Gestalt function returns information by setting or clearing bits in the response parameter. The bits relevant to the Sound Input Manager are defined by constants:
  6299. CONST
  6300.     gestaltSoundIOMgrPresent                                    = 3;            {sound input routines available}
  6301.     gestaltBuiltInSoundInput                                    = 4;            {built-in input hw available}
  6302.     gestaltHasSoundInputDevice                                    = 5;            {sound input device available}
  6303.     gestaltPlayAndRecord                                    = 6;            {built-in hw can play while recording}
  6304.     gestalt16BitSoundIO                                     = 7;            {built-in hw can handle 16-bit data}
  6305.     gestaltStereoInput                                     = 8;            {built-in hw can record stereo sounds}
  6306.     gestaltLineLevelInput                                     = 9;            {built-in input hw needs line level}
  6307. Constant descriptions
  6308. gestaltSoundIOMgrPresent
  6309. Set if the Sound Input Manager is available.
  6310. gestaltBuiltInSoundInput
  6311. Set if a built-in sound input device is available.
  6312. gestaltHasSoundInputDevice
  6313. Set if a sound input device is available. This device can be either built-in or external.
  6314. gestaltPlayAndRecord
  6315. Set if the built-in sound hardware is able to play and record sounds simultaneously. If this bit is clear, the built-in sound hardware can either play or record, but not do both at once. This bit is valid only if the gestaltBuiltInSoundInput bit is set, and it applies only to any built-in sound input and output hardware.
  6316. gestalt16BitSoundIO
  6317. Set if the built-in sound hardware is able to play and record 16-bit samples. This indicates that built-in hardware necessary to handle 16-bit data is available.
  6318. gestaltStereoInput
  6319. Set if the built-in sound hardware can record stereo sounds.
  6320. gestaltLineLevelInput
  6321. Set if the built-in sound input port requires line level input.
  6322. Note
  6323. For complete information about the Gestalt function, see the chapter “Gestalt Manager” in Inside Macintosh: Operating System Utilities.u
  6324. Sound Input Device Information Selectors
  6325.  
  6326. You can call the SPBSetDeviceInfo and SPBGetDeviceInfo functions to set or get information about a sound input device. You pass each of those functions a sound input device information selector in the infoType parameter to specify the type of information you need. The available device information selectors are defined by constants.
  6327. IMPORTANT
  6328. IMPORTANT
  6329. Some of these selectors are intended for use only by the Sound Input Manager and other parts of the system software that need to interact directly with sound input device drivers. (For example, the Sound Input Manager sends the siCloseDriver selector to a sound input device driver when it is closing the device.) In general, applications should not use these reserved selectors.s
  6330. CONST
  6331.     siActiveChannels                                = 'chac';                {channels active}
  6332.     siActiveLevels                                = 'lmac';                {levels active}
  6333.     siAGCOnOff                                = 'agc ';                {automatic gain control state}
  6334.     siAsync                                = 'asyn';                {asynchronous capability}
  6335.     siChannelAvailable                                = 'chav';                {number of channels available}
  6336.     siCloseDriver                                = 'clos';                {reserved for internal use only}
  6337.     siCompressionAvailable                                = 'cmav';                {compression types available}
  6338.     siCompressionFactor                                = 'cmfa';                {current compression factor}
  6339.     siCompressionHeader                                = 'cmhd';                {return compression header}
  6340.     siCompressionNames                                = 'cnam';                {return compression type names}
  6341.     siCompressionType                                = 'comp';                {current compression type}
  6342.     siContinuous                                = 'cont';                {continuous recording}
  6343.     siDeviceBufferInfo                                = 'dbin';                {size of interrupt buffer}
  6344.     siDeviceConnected                                = 'dcon';                {input device connection status}
  6345.     siDeviceIcon                                = 'icon';                {input device icon}
  6346.     siDeviceName                                = 'name';                {input device name}
  6347.     siInitializeDriver                                = 'init';                {reserved for internal use only}
  6348.     siInputGain                                = 'gain';                {input gain level}
  6349.     siInputSource                                = 'sour';                {input source selector}
  6350.     siInputSourceNames                                = 'snam';                {input source names}
  6351.     siLevelMeterOnOff                                = 'lmet';                {level meter state}
  6352.     siNumberChannels                                = 'chan';                {current number of channels}
  6353.     siOptionsDialog                                = 'optd';                {display options dialog box}
  6354.     siPauseRecording                                = 'paus';                {reserved for internal use only}
  6355.     siPlayThruOnOff                                = 'plth';                {play-through state}
  6356.     siRecordingQuality                                = 'qual';                {recording quality}
  6357.     siSampleRate                                = 'srat';                {current sample rate}
  6358.     siSampleRateAvailable                                = 'srav';                {sample rates available}
  6359.     siSampleSize                                = 'ssiz';                {current sample size}
  6360.     siSampleSizeAvailable                                = 'ssav';                {sample sizes available}
  6361.     siStereoInputGain                                = 'sgai';                {stereo input gain level}
  6362.     siTwosComplementOnOff                                = 'twos';                {two's complement state}
  6363.     siUserInterruptProc                                = 'user';                {reserved for internal use only}
  6364.     siVoxRecordInfo                                = 'voxr';                {VOX record parameters}
  6365.     siVoxStopInfo                                = 'voxs';                {VOX stop parameters}
  6366. Constant descriptions
  6367. siActiveChannels
  6368. Get or set the channels to record from. When setting the active channels, the data passed in is a long integer that is interpreted as a bitmap describing the channels to record from. For example, if bit 0 is set, then the first channel is made active. The samples for each active channel are interleaved in the application’s buffer. When reading the active channels, the data returned is a bitmap of the active channels.
  6369. siActiveLevels
  6370. Get the current signal level for each active channel. The infoData parameter points to an array of integers, the size of which depends on the number of active channels. You can determine how many channels are active by calling SPBGetDeviceInfo with the siNumberChannels selector.
  6371. siAGCOnOff    Get or set the current state of the automatic gain control feature. The infoData parameter points to an integer, which is 0 if gain control is off and 1 if it is on.
  6372. siAsync    Determine whether the driver supports asynchronous recording functions. The infoData parameter points to an integer, which is 0 if the driver supports synchronous calls only and 1 otherwise. Some sound input drivers do not support asynchronous recording at all, and some might support asynchronous recording only on certain hardware configurations.
  6373. siChannelAvailable
  6374. Get the maximum number of channels this device can record. The infoData parameter points to an integer, which is the number of available channels.
  6375. siCloseDriver    The Sound Input Manager sends this selector when it closes a device previously opened with write permission. The sound input device driver should stop any recording in progress, deallocate the input hardware, and initialize local variables to default settings. Your application should never issue this selector directly. The infoData parameter is unused with this selector.
  6376. siCompressionAvailable
  6377. Get the number and list of compression types this device can produce. The infoData parameter points to an integer, which is the number of compression types, followed by a handle. The handle references a list of compression types, each of type OSType.
  6378. siCompressionFactor
  6379. Get the compression factor of the current compression type. For example, the compression factor for MACE 3:1 compression is 3. If a sound input device driver supports only compression type 'NONE', the returned compression type is 1. The infoData parameter points to an integer, which is the compression factor.
  6380. siCompressionHeader
  6381. Get a compressed sound header for the current recording settings. Your application passes in a pointer to a compressed sound header and the driver fills it in. Before calling SPBGetDeviceInfo with this selector, you should set the numFrames field of the compressed sound header to the number of bytes in the sound. When SPBGetDeviceInfo returns successfully, that field contains the number of sample frames in the sound. This selector is needed only by drivers that use compression types that are not directly supported by Apple. If you call this selector after recording a sound, your application can get enough information about the sound to play it or save it in a file. The infoData parameter points to a compressed sound header.
  6382. siCompressionNames
  6383. Get a list of names of the compression types supported by the sound input device. In response to a Status call, a sound input device driver returns, in the location specified by the infoData parameter, a handle to a block of memory that contains the names of all compression types supported by the driver. It is the driver’s responsibility to allocate that block of memory, but it should not release it. The software issuing this selector is responsible for disposing of the handle. As a result, a device driver must detach any resource handles (by calling DetachResource) before returning them to the caller. The data in the handle has the same format as an 'STR#' resource: a two-byte count of the strings in the resource, followed by the strings themselves. The strings should occur in the same order as the compression types returned by the siCompressionAvailable selector. If the driver does not support compression, it returns siUnknownInfoType. If the driver supports compression but for some reason not all compression types are currently selectable, it returns a list of all available compression types.
  6384. siCompressionType
  6385. Get or set the compression type. Some devices allow the incoming samples to be compressed before being placed in your application’s input buffer. The infoData parameter points to a buffer of type OSType, which is the compression type.
  6386. siContinuous    Get or set the state of continuous recording from this device. If recording is being turned off, the driver stops recording samples to its internal buffer. Only sound input device drivers that support asynchronous recording support continuous recording. The infoData parameter points to an integer, which is the state of continuous recording (0 is off, 1 is on).
  6387. siDeviceBufferInfo
  6388. Get the size of the device’s internal buffer. This information can be useful when you want to modify sound input data at interrupt time. Note, however, that if a driver is recording continuously, then the size of the buffer passed to your sound input interrupt routine might be greater than the size this selector returns because data recorded between calls to SPBRecord as well as recorded during calls to SPBRecord will be sent to your interrupt routine. The infoData parameter points to a long integer, which is the size of the device’s internal buffer.
  6389. siDeviceConnected
  6390. Get the state of the device connection. The infoData parameter points to an integer, which is one of the following constants:
  6391.                     CONST
  6392.                         siDeviceIsConnected                                = 1;
  6393.                         siDeviceNotConnected                                = 0;
  6394.                         siDontKnowIfConnected                                = -1;
  6395.     The siDeviceIsConnected constant indicates that the device is connected and ready. The siDeviceNotConnected constant indicates that the device is not connected. The siDontKnowIfConnected constant indicates that the Sound Input Manager cannot determine whether the device is connected.
  6396. siDeviceIcon    Get the device’s icon and icon mask. In response to a Status call, a sound input device driver should return, in the location specified by the infoData parameter, a handle to a block of memory that contains the icon and its mask in the format of an 'ICN#' resource. It is the driver’s responsibility to allocate that block of memory, but it should not releasee it. The software issuing this selector is responsible for disposing of the handle. As a result, a device driver should detach any resource handles (by calling DetachResource) before returning them to the caller.
  6397. siDeviceName    Get the name of the sound input device. Your application must pass a pointer to a buffer that will be filled in with the device’s name. The buffer needs to be large enough to hold a Str255 data type.
  6398. siInitializeDriver
  6399. The Sound Input Manager sends this selector when it opens a sound input device with write permission. The sound input device driver initializes local variables and prepares to start recording. If possible, the driver initializes the device to a sampling rate of 22 kHz, a sample size of 8 bits, mono recording, no compression, automatic gain control on, and all other features off. Your application should never issue this selector directly. The infoData parameter is unused with this selector.
  6400. siInputGain    Get and set the current sound input gain. If the available hardware allows adjustment of the recording gain, this selector lets you get and set the gain. In response to a Status call, a sound input driver returns the current gain setting. In response to a Control call, a sound input driver sets the gain level used for all subsequent recording to the specified value. The infoData parameter points to a 4-byte value of type Fixed ranging from 0.5 to 1.5, where 1.5 specifies maximum gain.
  6401. siInputSource    Get and set the current sound input source. If the available hardware allows recording from more than one source, this selector lets you get and set the source. In response to a Status call, a sound input driver returns the current source value; if the driver supports only one source, it returns siUnknownInfoType. In response to a Control call, a sound input driver sets the source of all subsequent recording to the value passed in. If the value is less than 1 or greater than the number of input sources, the driver returns paramErr; if the driver supports only one source, it returns siUnknownInfoType. The infoData parameter points to an integer, which is the index of the current sound input source.
  6402. siInputSourceNames
  6403. Get a list of the names of all the sound input sources supported by the sound input device. In response to a Status call, a sound input device driver returns, in the location specified by the infoData parameter, a handle to a block of memory that contains the names of all sound sources supported by the driver. It is the driver’s responsibility to allocate that block of memory, but it should not release it. The software issuing this selector is responsible for disposing of the handle. As a result, a device driver must detach any resource handles (by calling DetachResource) before returning them to the caller. The data in the handle has the same format as an 'STR#' resource: a two-byte count of the strings in the resource, followed by the strings themselves. The strings should occur in the same order as the input sources returned by the siInputSource selector. If the driver supports only one source, it returns siUnknownInfoType. If the driver supports more than one source but for some reason not all of them are currently selectable, it returns a list of all available input sources.
  6404. siLevelMeterOnOff
  6405. Get or set the current state of the level meter. For calls to set the level meter, the infoData parameter points to an integer that indicates whether the level meter is off (0) or on (1). To get the level meter setting, the infoData parameter points to two integers; the first integer indicates the state of the level meter, and the second integer contains the level value of the meter. The level meter setting is an integer that ranges from 0 (no volume) to 255 (full volume). 
  6406. siNumberChannels
  6407. Get or set the number of channels this device is to record. The infoData parameter points to an integer, which indicates the number of channels. Note that this selector determines the format of the data stream output by the driver. If the number of channels is 1, the driver should output monophonic data in response to a Read call. If the number of channels is 2, the driver should output interleaved stereo data.
  6408. siOptionsDialog
  6409. Determine whether the driver supports an Options dialog box (SPBGetDeviceInfo) or cause the driver to display the Options dialog box (SPBSetDeviceInfo). This dialog box is designed to allow the user to configure device-specific features of the sound input hardware. With SPBGetDeviceInfo, the infoData parameter points to an integer, which indicates whether the driver supports an Options dialog box (1 if it supports it, 0 otherwise). With SPBSetDeviceInfo, the infoData parameter is unused.
  6410. siPauseRecording
  6411. The Sound Input Manager uses this selector to get or set the current pause state. The sound input device driver continues recording but does not store the sampled data in a buffer. Your application should never issue this selector directly. The infoData parameter points to an integer, which indicates the state of pausing (0 is off, 1 is on).
  6412. siPlayThruOnOff
  6413. Get or set the current play-through state and volume. The infoData parameter points to an integer, which indicates the current play-through volume (1 to 7). If that integer is 0, then play-through is off.
  6414. siRecordingQuality
  6415. Get or set the current quality of recorded sound. The infoData parameter points to a buffer of type OSType, which is the recording quality. Currently three qualities are supported, defined by these constants:
  6416.                                     CONST
  6417.                                         siBestQuality                                = 'best';
  6418.                                         siBetterQuality                                = 'betr';
  6419.                                         siGoodQuality                                = 'good';
  6420.     These qualities are defined by the sound input device driver. Usually best means monaural, 8-bit, 22 kHz, sound with no compression.
  6421. siSampleRate    Get or set the sample rate to be produced by this device. The sample rate must be in the range 0 to 65535.65535 Hz. The sample rate is declared as a Fixed data type. In order to accommodate sample rates greater than 32 kHz, the most significant bit is not treated as a sign bit; instead, that bit is interpreted as having the value 32,768. The infoData parameter points to a buffer of type Fixed, which is the sample rate.
  6422. siSampleRateAvailable
  6423. Get the range of sample rates this device can produce. The infoData parameter points to an integer, which is the number of sample rates the device supports, followed by a handle. The handle references a list of sample rates, each of type Fixed. If the device can record a range of sample rates, the number of sample rates is set to 0 and the handle contains two rates, the minimum and the maximum of the range of sample rates. Otherwise, a list is returned that contains the sample rates supported. In order to accommodate sample rates greater than 32 kHz, the most significant bit is not treated as a sign bit; instead, that bit is interpreted as having the value 32,768.
  6424. siSampleSize    Get or set the sample size to be produced by this device. Because some compression formats require specific sample sizes, this selector might return an error when compression is used. The infoData parameter points to an integer, which is the sample size.
  6425. siSampleSizeAvailable
  6426. Get the range of sample sizes this device can produce. The infoData parameter points to an integer, which is the number of sample sizes the device supports, followed by a handle. The handle references a list of sample sizes, each of type Integer.
  6427. siStereoInputGain
  6428. Get and set the current stereo sound input gain. If the available hardware allows adjustment of the recording gain, this selector lets you get and set the gain for each of two channels (left or right). In response to a Status call, a sound input driver should return the current gain setting for the specified channel. In response to a Control call, a sound input driver should set the gain level used for all subsequent recording to the specified value. The infoData parameter points to two 4-byte values of type Fixed ranging from 0.5 to 1.5, where 1.5 specifies maximum gain. The first of these values is equivalent to the gain for the left channel and the second value is equivalent to the gain for the right channel.
  6429. siTwosComplementOnOff
  6430. Get or set the current state of the two’s complement feature. This selector only applies to 8-bit data. (16-bit samples are always stored in two’s complement format.) If on, the driver stores all samples in the application buffer as two’s complement values (that is, –128 to 127). Otherwise, the driver stores the samples as offset binary values (that is, 0 to 255). The infoData parameter points to an integer, which is the current state of the two’s complement feature (1 if two’s complement output is desired, 0 otherwise).
  6431. siUserInterruptProc
  6432. The Sound Input Manager sends this selector to specify the sound input interrupt routine that the sound input device driver should call. Your application should never issue this selector directly. The infoData parameter points to a procedure pointer, which is the address of the sound input interrupt routine.
  6433. siVoxRecordInfo
  6434. Get or set the current VOX recording parameters. The infoData parameter points to two integers. The first integer indicates whether VOX recording is on or off (0 if off, 1 if on). The second integer indicates the VOX record trigger value. Trigger values range from 0 to 255 (0 is trigger immediately, 255 is trigger only on full volume).
  6435. siVoxStopInfo    Get or set the current VOX stopping parameters. The infoData parameter points to three integers. The first integer indicates whether VOX stopping is on or off (0 if off, 1 if on). The second integer indicates the VOX stop trigger value. Trigger values range from 0 to 255 (255 is stop immediately, 0 is stop only on total silence). The third integer indicates how many milliseconds the trigger value must be continuously valid for recording to be stopped. Delay values range from 0 to 65,535.
  6436. Data Structures
  6437.  
  6438. This section describes the sound input parameter block.
  6439. Sound Input Parameter Blocks
  6440.  
  6441. The SPBRecord and SPBRecordToFile functions require a pointer to a sound input parameter block that defines characteristics of the recording. If you define a sound input completion routine or a sound input interrupt routine, your routine receives a pointer to a sound input parameter block. If you are using only the Sound Input Manager’s high-level SndRecord and SndRecordToFile functions, the operation of sound input parameter blocks is transparent to your application. A sound input parameter block is defined by the SPB data type.
  6442. TYPE SPB =
  6443. RECORD
  6444.     inRefNum:                            LongInt;                {reference number of input device}
  6445.     count:                            LongInt;                {number of bytes to record}
  6446.     milliseconds:                            LongInt;                {number of milliseconds to record}
  6447.     bufferLength:                            LongInt;                {length of buffer to record into}
  6448.     bufferPtr:                            Ptr;                {pointer to buffer to record into}
  6449.     completionRoutine:                            ProcPtr;                {pointer to a completion routine}
  6450.     interruptRoutine:                            ProcPtr;                {pointer to an interrupt routine}
  6451.     userLong:                            LongInt;                {for application's use}
  6452.     error:                            OSErr;                {error returned after recording}
  6453.     unused1:                            LongInt;                {reserved}
  6454. END;
  6455. Field descriptions
  6456. inRefNum    The reference number of the sound input device (as received from the SPBOpenDevice function) from which the recording is to occur.
  6457. count    On input, the number of bytes to record. On output, the number of bytes actually recorded. If this field specifies a longer recording time than the milliseconds field, then the milliseconds field is ignored on input.
  6458. milliseconds    On input, the number of milliseconds to record. On output, the number of milliseconds actually recorded. If this field specifies a longer recording time than the count field, then the count field is ignored on input.
  6459. bufferLength    The length of the buffer into which recorded sound data is placed. The recording time specified by the count or milliseconds field is truncated to fit into this length, if necessary.
  6460. bufferPtr    A pointer to the buffer into which recorded data is placed. If this field is NIL, then the count, milliseconds, and bufferLength fields are ignored and the recording will continue indefinitely until the SPBStopRecording function is called. However, the data is not stored anywhere, so setting this field to NIL is useful only if you want to do something in a sound input interrupt routine but do not want to save the recorded sound.
  6461. completionRoutine
  6462. A pointer to a completion routine that is called when the recording terminates as a result of your calling the SPBStopRecording function or when the limit specified by the count or milliseconds field is reached. The completion routine executes only if SPBRecord is called asynchronously and therefore is called at interrupt time.
  6463. interruptRoutine
  6464. A pointer to a routine that is called by asynchronous recording devices when their internal buffers are full. You can define a sound input interrupt routine to modify uncompressed sound samples before they are placed into the buffer specified in the bufferPtr parameter. The interrupt routine executes only if SPBRecord is called asynchronously and therefore is called at interrupt time.
  6465. userLong    A long integer available for the application’s own use. You can use this field, for instance, to pass a handle to an application-defined structure to the completion routine or to the interrupt routine.
  6466. error    On exit, the error that occurred during recording. This field contains a value greater than 0 while recording unless an error occurs, in which case it contains a value less than 0 that indicates an operating system error. Your application can poll this field to check on the status of an asynchronous recording. If recording terminates without an error, this field contains 0.
  6467. unused1    Reserved for use by Apple. You should always initialize this field to 0.
  6468. Sound Input Manager Routines
  6469.  
  6470. This section describes the routines provided by the Sound Input Manager. You can use these routines to
  6471. n    record sounds using the sound recording dialog box
  6472. n    open and close sound input devices
  6473. n    record sounds directly from sound input devices
  6474. n    get information about sound input devices and change device settings
  6475. n    construct sound resource and file headers
  6476. n    register sound input devices with the Sound Input Manager
  6477. n    convert recording times between millisecond and byte values
  6478. n    obtain information about the version of the Sound Input Manager that is running
  6479. The section “Application-Defined Routines” on page 3-53 describes the format of sound input completion routines and sound input interrupt routines.
  6480. Recording Sounds
  6481.  
  6482. The Sound Input Manager provides two high-level sound input functions, SndRecord and SndRecordToFile, for recording sound. These input routines are analogous to the two Sound Manager functions SndPlay and SndStartFilePlay. By using these high-level routines, you can be assured that your application presents a user interface that is consistent with that displayed by other applications doing sound input. Both SndRecord and SndRecordToFile attempt to record sound data from the sound input hardware currently selected in the Sound In control panel.
  6483. SndRecord
  6484.  
  6485. You can use the SndRecord function to record sound resources into memory.
  6486. FUNCTION SndRecord (filterProc: ProcPtr; corner: Point; 
  6487.                             quality: OSType; VAR sndHandle: Handle): 
  6488.                             OSErr;
  6489. filterProc
  6490. A pointer to an event filter function that determines how user actions in the sound recording dialog box are filtered (similar to the filterProc parameter specified in a call to the ModalDialog procedure). By specifying your own filter function, you can override or add to the default actions of the items in the dialog box. If filterProc isn’t NIL, SndRecord filters events by calling the function that filterProc points to.
  6491. corner    The horizontal and vertical coordinates of the upper-left corner of the sound recording dialog box (in global coordinates).
  6492. quality    The desired quality of the recorded sound.
  6493. sndHandle    On entry, a handle to some storage space or NIL. On exit, a handle to a valid sound resource (or unchanged, if the call did not execute successfully).
  6494. DESCRIPTION
  6495. The SndRecord function records sound into memory. The recorded data has the structure of a format 1 'snd ' resource and can later be played using the SndPlay function or can be stored as a resource. SndRecord displays a sound recording dialog box and is always called synchronously. Controls in the dialog box allow the user to start, stop, pause, and resume sound recording, as well as to play back the recorded sound. The dialog box also lists the remaining recording time and the current microphone sound level.
  6496. The quality parameter defines the desired quality of the recorded sound. Currently, three values are recognized for the quality parameter:
  6497. CONST
  6498.     siBestQuality                            = 'best';                {the best quality available}
  6499.     siBetterQuality                            = 'betr';                {a quality better than good}
  6500.     siGoodQuality                            = 'good';                {a good quality}
  6501. The precise meanings of these parameters are defined by the sound input device driver. For Apple-supplied drivers, this parameter determines whether the recorded sound is to be compressed, and if so, whether at a 6:1 or a 3:1 ratio. The quality siBestQuality does not compress the sound and provides the best quality output, but at the expense of increased memory use. The quality siBetterQuality is suitable for most nonvoice recording, and siGoodQuality is suitable for voice recording.
  6502. The sndHandle parameter is a handle to some storage space. If the handle is NIL, the Sound Input Manager allocates a handle of the largest amount of space that it can find in your application’s heap and returns this handle in the sndHandle parameter. The Sound Input Manager resizes the handle when the user clicks the Save button in the sound recording dialog box. If the sndHandle parameter passed to SndRecord is not NIL, the Sound Input Manager simply stores the recorded data in the location specified by that handle.
  6503. SPECIAL CONSIDERATIONS
  6504. Because the SndRecord function moves memory, you should not call it at interrupt time.
  6505. ASSEMBLY-LANGUAGE INFORMATION
  6506. The trap macro and routine selector for the SndRecord function are
  6507. Trap macro    Selector    
  6508. _SoundDispatch    $08040014    
  6509.  
  6510. RESULT CODESnoErr    0    No error    
  6511. userCanceledErr    –128    User canceled the operation    
  6512. siBadSoundInDevice    –221    Invalid sound input device    
  6513. siUnknownQuality    –232    Unknown quality    
  6514.  
  6515. SEE ALSO
  6516. See the chapter “Dialog Manager” in Inside Macintosh: Macintosh Toolbox Essentials for a complete description of event filter functions.
  6517. SndRecordToFile
  6518.  
  6519. You can use SndRecordToFile to record sound data into a file.
  6520. FUNCTION SndRecordToFile (filterProc: ProcPtr; corner: Point; 
  6521.                                     quality: OSType; 
  6522.                                     fRefNum: Integer): OSErr;
  6523. filterProc
  6524. A pointer to a function that determines how user actions in the sound recording dialog box are filtered.
  6525. corner    The horizontal and vertical coordinates of the upper-left corner of the sound recording dialog box (in global coordinates).
  6526. quality    The desired quality of the recorded sound, as described on page 3-28.
  6527. fRefNum    The file reference number of an open file to save the audio data in.
  6528. DESCRIPTION
  6529. The SndRecordToFile function works just like SndRecord except that it stores the sound input data into a file. The resulting file is in either AIFF or AIFF-C format and contains the information necessary to play the file by using the Sound Manager’s SndStartFilePlay function. The SndRecordToFile function is always called synchronously.
  6530. Your application must open the file specified in the fRefNum parameter before calling the SndRecordToFile function. Your application must close the file sometime after calling SndRecordToFile.
  6531. SPECIAL CONSIDERATIONS
  6532. Because the SndRecordToFile function moves memory, you should not call it at interrupt time.
  6533. ASSEMBLY-LANGUAGE INFORMATION
  6534. The trap macro and routine selector for the SndRecordToFile function are
  6535. Trap macro    Selector    
  6536. _SoundDispatch    $07080014    
  6537.  
  6538. RESULT CODESnoErr    0    No error    
  6539. userCanceledErr    –128    User canceled the operation    
  6540. siBadSoundInDevice    –221    Invalid sound input device    
  6541. siUnknownQuality    –232    Unknown quality    
  6542.  
  6543. Opening and Closing Sound Input Devices
  6544.  
  6545. You can use the SPBOpenDevice function to open the default sound input device that the user has selected in the Sound In control panel or to open a specific sound input device. You must open a device before you can record from it by using SPBRecord, but the Sound Input Manager’s high-level routines automatically open the default sound input device. You can close a sound input device by calling the SPBCloseDevice function.
  6546. SPBOpenDevice
  6547.  
  6548. You can use the SPBOpenDevice function to open a sound input device.
  6549. FUNCTION SPBOpenDevice (deviceName: Str255; permission: Integer; 
  6550.                                 VAR inRefNum: LongInt): OSErr;
  6551. deviceName
  6552. The name of the sound input device to open, or the empty string if the default sound input device is to be opened.
  6553. permission
  6554. A flag that indicates whether subsequent operations with that device are to be read/write or read-only.
  6555. inRefNum    On exit, if the function is successful, a device reference number for the open sound input device.
  6556. DESCRIPTION
  6557. The SPBOpenDevice function attempts to open a sound input device having the name indicated by the deviceName parameter. If SPBOpenDevice succeeds, it returns a device reference number in the inRefNum parameter. The permission parameter indicates whether subsequent operations with that device are to be read/write or read-only. If the device is not already in use, read/write permission is granted; otherwise, only read-only operations are allowed. To make any recording requests or to call the SPBSetDeviceInfo function, read/write permission must be available. Use these constants to request the appropriate permission:
  6558. CONST
  6559.     siReadPermission                            = 0;            {open device for reading}
  6560.     siWritePermission                            = 1;            {open device for reading/writing}
  6561. You can request that the current default sound input device be opened by passing either a zero-length string or a NIL string as the deviceName parameter. If only one sound input device is installed, that device is used. Generally you should open the default device unless you specifically want to use some other device. You can get a list of the available devices by calling the SPBGetIndexedDevice function.
  6562. SPECIAL CONSIDERATIONS
  6563. Because the SPBOpenDevice function allocates memory, you should not call it at interrupt time.
  6564. ASSEMBLY-LANGUAGE INFORMATION
  6565. The trap macro and routine selector for the SPBOpenDevice function are
  6566. Trap macro    Selector    
  6567. _SoundDispatch    $05180014    
  6568.  
  6569. RESULT CODESnoErr    0    No error    
  6570. permErr    –54    Device already open for writing    
  6571. siBadDeviceName    –228    Invalid device name    
  6572.  
  6573. SPBCloseDevice 
  6574.  
  6575. You can use the SPBCloseDevice function to close a sound input device.
  6576. FUNCTION SPBCloseDevice (inRefNum: LongInt): OSErr;
  6577. inRefNum    The device reference number of the sound input device to close.
  6578. DESCRIPTION
  6579. The SPBCloseDevice function closes a device that was previously opened by SPBOpenDevice and whose device reference number is specified in the inRefNum parameter.
  6580. SPECIAL CONSIDERATIONS
  6581. Because the SPBCloseDevice function moves or purges memory, you should not call it at interrupt time.
  6582. ASSEMBLY-LANGUAGE INFORMATION
  6583. The trap macro and routine selector for the SPBCloseDevice function are
  6584. Trap macro    Selector    
  6585. _SoundDispatch    $021C0014    
  6586.  
  6587. RESULT CODESnoErr    0    No error    
  6588. siBadRefNum    –229    Invalid reference number    
  6589.  
  6590. Recording Sounds Directly From Sound Input Devices
  6591.  
  6592. The Sound Input Manager provides a number of routines that allow you to begin, pause, resume, and stop recording directly from a sound input device. These low-level routines do not display the sound recording dialog box to the user.
  6593. SPBRecord
  6594.  
  6595. You can use the SPBRecord function to record audio data into memory, either synchronously or asynchronously.
  6596. FUNCTION SPBRecord (inParamPtr: SPBPtr; asynchFlag: Boolean): 
  6597.                             OSErr;
  6598. inParamPtr
  6599. A pointer to a sound input parameter block.
  6600. asynchFlag
  6601. A Boolean value that specifies whether the recording occurs asynchronously (TRUE) or synchronously (FALSE).
  6602. You specify values and receive return values in the sound input parameter block.
  6603. Parameter block    Æ    inRefNum    LongInt    A reference number of a sound input device.    
  6604. ´    count    LongInt    The number of bytes of recording.    
  6605. ´    milliseconds    LongInt    The number of milliseconds of recording.    
  6606. Æ    bufferLength    LongInt    The length of the buffer beginning at bufferPtr.    
  6607. Æ    bufferPtr    Ptr    A pointer to a buffer for sampled-sound data.    
  6608. Æ    completionRoutine    ProcPtr    A pointer to a completion routine.    
  6609. Æ    interruptRoutine    ProcPtr    A pointer to an interrupt routine.    
  6610. Æ    userLong    LongInt    Free for application’s use.    
  6611. ¨    error    OSErr    The error value returned after recording.    
  6612. Æ    unused1    LongInt    Reserved.    
  6613.  
  6614. Field descriptions
  6615. inRefNum    The device reference number of the sound input device, as obtained from the SPBOpenDevice function.
  6616. count    On input, the number of bytes to record. If this field indicates a longer recording time than the milliseconds field, then the milliseconds field is ignored. On output, this field indicates the number of bytes actually recorded.
  6617. milliseconds    On input, the number of milliseconds to record. If this field indicates a longer recording time than the count field, then the count field is ignored. On output, this field indicates the number of milliseconds actually recorded.
  6618. bufferLength    The number of bytes in the buffer specified by the bufferPtr parameter. If this buffer length is too small to contain the amount of sampled-sound data specified in the count and milliseconds fields, then recording time is truncated so that the sampled-sound data fits in the buffer.
  6619. bufferPtr    A pointer to the buffer for the sampled-sound data, or NIL if you wish to record sampled-sound data without saving it. On exit, this buffer contains the sampled-sound data, which is interleaved for stereo sound on a sample basis (or on a packet basis if the data is compressed). This buffer contains only sampled-sound data, so if you need a sampled sound header, you should set that up in a buffer before calling SPBRecord and then record into the buffer following the sound header.
  6620. completionRoutine
  6621. A pointer to a completion routine. This routine is called when the recording terminates (either after you call the SPBStopRecording function or when the prescribed limit is reached). The completion routine is called only for asynchronous recording.
  6622. interruptRoutine
  6623. A pointer to an interrupt routine. The interrupt routine specified in the interruptRoutine field is called by asynchronous recording devices when their internal buffers are full.
  6624. userLong    A long integer that your application can use to pass data to your application’s completion or interrupt routines.
  6625. error    On exit, a value greater than 0 while recording unless an error occurs, in which case it contains a value less than 0 that indicates an operating system error. Your application can poll this field to check on the status of an asynchronous recording. If recording terminates without an error, this field contains 0.
  6626. unused1    Reserved. You should set this field to 0 before calling SPBRecord.
  6627. DESCRIPTION
  6628. The SPBRecord function starts recording into memory from a device specified in a sound input parameter block. The sound data recorded is stored in the buffer specified by the bufferPtr and bufferLength fields of the parameter block. Recording lasts the longer of the times specified by the count and milliseconds fields of the parameter block, or until the buffer is filled. Recording is asynchronous if the asynchFlag parameter is TRUE and the specified sound input device supports asynchronous recording.
  6629. If the bufferPtr field of the parameter block contains NIL, then the count, milliseconds, and bufferLength fields are ignored, and the recording continues indefinitely until you call the SPBStopRecording function. In this case, the audio data is not saved anywhere; this feature is useful only if you want to do something in your interrupt routine and do not want to save the audio data. However, if the recording is synchronous and bufferPtr is NIL, SPBRecord returns the result code siNoBufferSpecified.
  6630. The SPBRecord function returns the value that the error field of the parameter block contains when recording finishes.
  6631. SPECIAL CONSIDERATIONS
  6632. You can call the SPBRecord function at interrupt time.
  6633. ASSEMBLY-LANGUAGE INFORMATION
  6634. The trap macro and routine selector for the SPBRecord function are
  6635. Trap macro    Selector    
  6636. _SoundDispatch    $03200014    
  6637.  
  6638. RESULT CODESnoErr    0    No error    
  6639. siNoSoundInHardware    –220    No sound input hardware available    
  6640. siBadSoundInDevice    –221    Invalid sound input device    
  6641. siNoBufferSpecified    –222    No buffer specified    
  6642. siDeviceBusyErr    –227    Sound input device is busy    
  6643.  
  6644. SEE ALSO
  6645. For an example of the use of the SPBRecord function, see Listing 3-1.
  6646. SPBRecordToFile
  6647.  
  6648. You can use the SPBRecordToFile function to record audio data into a file, either synchronously or asynchronously.
  6649. FUNCTION SPBRecordToFile (fRefNum: Integer; inParamPtr: SPBPtr; 
  6650.                                     asynchFlag: Boolean): OSErr;
  6651. fRefNum    The file reference number of an open file in which to place the recorded sound data.
  6652. inParamPtr
  6653. A pointer to a sound input parameter block.
  6654. asynchFlag
  6655. A Boolean value that specifies whether the recording occurs asynchronously (TRUE) or synchronously (FALSE).
  6656. Parameter blockÆ    inRefNum    LongInt    A reference number of a sound input device.    
  6657. ´    count    LongInt    The number of bytes of recording.    
  6658. ´    milliseconds    LongInt    The number of milliseconds of recording.    
  6659. Æ    completionRoutine    ProcPtr    A pointer to a completion routine.    
  6660. Æ    interruptRoutine    ProcPtr    Unused.    
  6661. Æ    userLong    LongInt    Free for application’s use.    
  6662. ¨    error    OSErr    The error value returned after recording.    
  6663. Æ    unused1    LongInt    Reserved.    
  6664.  
  6665. Field descriptions
  6666. inRefNum    The device reference number of the sound input device, as obtained from the SPBOpenDevice function.
  6667. count    On input, the number of bytes to record. If this field indicates a longer recording time than the milliseconds field, then the milliseconds field is ignored. On output, the number of bytes actually recorded.
  6668. milliseconds    On input, the number of milliseconds to record. If this field indicates a longer recording time than the count field, then the count field is ignored. On output, the number of milliseconds actually recorded.
  6669. completionRoutine
  6670. A pointer to a completion routine. This routine is called when the recording terminates (after you call the SPBStopRecording function, when the prescribed limit is reached, or after an error occurs). The completion routine is called only for asynchronous recording.
  6671. interruptRoutine
  6672. Unused. You should set this field to NIL before calling SPBRecordToFile.
  6673. userLong    A long integer that your application can use to pass data to your application’s completion or interrupt routines.
  6674. error    On exit, the error that occurred during recording. This field contains the number 1 while recording unless an error occurs, in which case it contains a value less than 0 that indicates an operating system error. Your application can poll this field to check on the status of an asynchronous recording. If recording terminates without an error, this field contains 0.
  6675. unused1    Reserved. You should set this field to 0 before calling the SPBRecordToFile function.
  6676. DESCRIPTION
  6677. The SPBRecordToFile function starts recording from the specified device into a file. The sound data recorded is simply stored in the file, so it is up to your application to insert whatever headers are needed to play the sound with the Sound Manager. Your application must open the file specified by the fRefNum parameter with write access before calling SPBRecordToFile, and it must eventually close that file.
  6678. The fields in the parameter block specified by the inParamPtr parameter are identical to the fields in the parameter block passed to the SPBRecord function, except that the bufferLength and bufferPtr fields are not used. The interruptRoutine field is ignored by SPBRecordToFile because SPBRecordToFile copies data returned by the sound input device driver to disk during the sound input interrupt routine, but you should initialize this field to NIL.
  6679. The SPBRecordToFile function writes samples to disk in the same format that they are read in from the sound input device. If compression is enabled, then the samples written to the file are compressed. Multiple channels of sound are interleaved on a sample basis (or, for compressed sound data, on a packet basis). When you are recording 8-bit audio data to an AIFF file, you must set the siTwosComplementOnOff flag to so that the data is stored on disk in the two’s-complement format. If you don’t store the data in this format, it sounds distorted when you play it back.
  6680. If any errors occur during the file writing process, recording is suspended. All File Manager errors are returned through the function’s return value if the routine is called synchronously. If the routine is called asynchronously and the completion routine is not NIL, the completion routine is called and is passed a single parameter on the stack that points to the sound input parameter block; any errors are returned in the error field of the sound input parameter block.
  6681. The SPBRecordToFile function returns the value that the error field of the parameter block contains when recording finishes.
  6682. SPECIAL CONSIDERATIONS
  6683. Because the SPBRecordToFile function moves or purges memory, you should not call it at interrupt time.
  6684. ASSEMBLY-LANGUAGE INFORMATION
  6685. The trap macro and routine selector for the SPBRecordToFile function are
  6686. Trap macro    Selector    
  6687. _SoundDispatch    $04240014    
  6688.  
  6689. RESULT CODESnoErr    0    No error    
  6690. permErr    –54    Attempt to open locked file for writing    
  6691. siNoSoundInHardware    –220    No sound input hardware available    
  6692. siBadSoundInDevice    –221    Invalid sound input device    
  6693. siHardDriveTooSlow    –224    Hard drive too slow to record    
  6694.  
  6695. SPBPauseRecording
  6696.  
  6697. You can use the SPBPauseRecording function to pause recording from a sound input device.
  6698. FUNCTION SPBPauseRecording (inRefNum: LongInt): OSErr;
  6699. inRefNum    The device reference number of the sound input device, as obtained from the SPBOpenDevice function.
  6700. DESCRIPTION
  6701. The SPBPauseRecording function pauses recording from the device specified by the inRefNum parameter. The recording must be asynchronous for this call to have any effect.
  6702. SPECIAL CONSIDERATIONS
  6703. You can call the SPBPauseRecording function at interrupt time.
  6704. ASSEMBLY-LANGUAGE INFORMATION
  6705. The trap macro and routine selector for the SPBPauseRecording function are
  6706. Trap macro    Selector    
  6707. _SoundDispatch    $02280014    
  6708.  
  6709. RESULT CODESnoErr    0    No error    
  6710. siBadSoundInDevice    –221    Invalid sound input device    
  6711.  
  6712. SPBResumeRecording
  6713.  
  6714. You can use the SPBResumeRecording function to resume recording from a sound input device.
  6715. FUNCTION SPBResumeRecording (inRefNum: LongInt): OSErr;
  6716. inRefNum    The device reference number of the sound input device, as obtained from the SPBOpenDevice function.
  6717. DESCRIPTION
  6718. The SPBResumeRecording function resumes recording from the device specified by the inRefNum parameter. Recording on that device must previously have been paused by a call to the SPBPauseRecording function for SPBResumeRecording to have any effect.
  6719. SPECIAL CONSIDERATIONS
  6720. You can call the SPBResumeRecording function at interrupt time.
  6721. ASSEMBLY-LANGUAGE INFORMATION
  6722. The trap macro and routine selector for the SPBResumeRecording function are
  6723. Trap macro    Selector    
  6724. _SoundDispatch    $022C0014    
  6725.  
  6726. RESULT CODESnoErr    0    No error    
  6727. siBadSoundInDevice    –221    Invalid sound input device    
  6728.  
  6729. SPBStopRecording
  6730.  
  6731. You can use the SPBStopRecording function to end a recording from a sound input device.
  6732. FUNCTION SPBStopRecording (inRefNum: LongInt): OSErr;
  6733. inRefNum    The device reference number of the sound input device, as obtained from the SPBOpenDevice function.
  6734. DESCRIPTION
  6735. The SPBStopRecording function stops recording from the device specified by the inRefNum parameter. The recording must be asynchronous for SPBStopRecording to have any effect. When you call SPBStopRecording, the sound input completion routine specified in the completionRoutine field of the sound input parameter block is called and the error field of that parameter block is set to abortErr. If you are writing a device driver, you will receive a KillIO Status call. See the section “Writing a Sound Input Device Driver” beginning on page 3-13 for more information.
  6736. SPECIAL CONSIDERATIONS
  6737. You can call the SPBStopRecording function at interrupt time.
  6738. ASSEMBLY-LANGUAGE INFORMATION
  6739. The trap macro and routine selector for the SPBStopRecording function are
  6740. Trap macro    Selector    
  6741. _SoundDispatch    $02300014    
  6742.  
  6743. RESULT CODESnoErr    0    No error    
  6744. siBadSoundInDevice    –221    Invalid sound input device    
  6745.  
  6746. SPBGetRecordingStatus
  6747.  
  6748. You can use SPBGetRecordingStatus to obtain recording status information about a sound input device.
  6749. FUNCTION SPBGetRecordingStatus (inRefNum: LongInt; 
  6750.                                     VAR recordingStatus: Integer; 
  6751.                                     VAR meterLevel: Integer; 
  6752.                                     VAR totalSamplesToRecord: LongInt; 
  6753.                                     VAR numberOfSamplesRecorded: LongInt; 
  6754.                                     VAR totalMsecsToRecord: LongInt; 
  6755.                                     VAR numberOfMsecsRecorded: LongInt):
  6756.                                     OSErr;
  6757. inRefNum    The device reference number of the sound input device, as obtained from the SPBOpenDevice function.
  6758. recordingStatus
  6759. The status of the recording. While the input device is recording, this parameter is set to a number greater than 0. When a recording terminates without an error, this parameter is set to 0. When an error occurs during recording or the recording has been terminated by a call to the SPBStopRecording function, this parameter is less than 0 and contains an error code.
  6760. meterLevel
  6761. The current input signal level. This level ranges from 0 to 255.
  6762. totalSamplesToRecord
  6763. The total number of samples to record, including those samples already recorded.
  6764. numberOfSamplesRecorded
  6765. The number of samples already recorded.
  6766. totalMsecsToRecord
  6767. The total duration of recording time, including recording time already elapsed.
  6768. numberOfMsecsRecorded
  6769. The amount of recording time that has elapsed.
  6770. DESCRIPTION
  6771. The SPBGetRecordingStatus function returns, in its second through seventh parameters, information about the recording on the device specified by the inRefNum parameter.
  6772. SPECIAL CONSIDERATIONS
  6773. You can call the SPBGetRecordingStatus function at interrupt time.
  6774. ASSEMBLY-LANGUAGE INFORMATION
  6775. The trap macro and routine selector for the SPBGetRecordingStatus function are
  6776. Trap macro    Selector    
  6777. _SoundDispatch    $0E340014    
  6778.  
  6779. RESULT CODESnoErr    0    No error    
  6780. siBadSoundInDevice    –221    Invalid sound input device    
  6781.  
  6782. Manipulating Device Settings
  6783.  
  6784. You can use the two functions SPBGetDeviceInfo and SPBSetDeviceInfo to read and change the settings of a sound input device.
  6785. SPBGetDeviceInfo
  6786.  
  6787. You can use the SPBGetDeviceInfo function to get information about the settings of a sound input device.
  6788. FUNCTION SPBGetDeviceInfo (inRefNum: LongInt; infoType: OSType;
  6789.                                         infoData: Ptr): OSErr;
  6790. inRefNum    The device reference number of the sound input device, as obtained from the SPBOpenDevice function.
  6791. infoType    A sound input device information selector that specifies the type of information you need.
  6792. infoData    A pointer to a buffer in which information should be returned. This buffer must be large enough for the type of information specified in the infoType parameter.
  6793. DESCRIPTION
  6794. The SPBGetDeviceInfo function returns information about the sound input device specified by the inRefNum parameter. The type of information you want is specified in the infoType parameter. The available sound input device information selectors are listed in “Sound Input Device Information Selectors” beginning on page 3-18. The information is copied into the buffer specified by the infoData parameter.
  6795. SPECIAL CONSIDERATIONS
  6796. Because the SPBGetDeviceInfo function might move memory, you should not call it at interrupt time. Check the selector description of the selector you want to use to see if it moves memory before calling the SPBGetDeviceInfo function. Most of the selectors do not move memory and are therefore safe to use at interrupt time.
  6797. ASSEMBLY-LANGUAGE INFORMATION
  6798. The trap macro and routine selector for the SPBGetDeviceInfo function are
  6799. Trap macro    Selector    
  6800. _SoundDispatch    $06380014    
  6801.  
  6802. RESULT CODESnoErr    0    No error    
  6803. siBadSoundInDevice    –221    Invalid sound input device    
  6804. siUnknownInfoType    –231    Unknown type of information    
  6805.  
  6806. SEE ALSO
  6807. Listing 3-2 on page 3-12 shows an example that uses the SPBGetDeviceInfo function to get the name of a sound input device driver.
  6808. SPBSetDeviceInfo
  6809.  
  6810. You can use the SPBSetDeviceInfo function to set information in a sound input device.
  6811. FUNCTION SPBSetDeviceInfo (inRefNum: LongInt; infoType: OSType; 
  6812.                                      infoData: Ptr): OSErr;
  6813. inRefNum    The device reference number of the sound input device, as obtained from the SPBOpenDevice function.
  6814. infoType    A sound input device information selector that specifies the type of information you need.
  6815. infoData    A pointer to a buffer. This buffer can contain information on entry, and information might be returned on exit. This buffer must be large enough for the type of information specified in the infoType parameter, and the data in the buffer must be set to appropriate values if information needs to be passed in to the SPBSetDeviceInfo function.
  6816. DESCRIPTION
  6817. The SPBSetDeviceInfo function sets information about the sound input device specified by the inRefNum parameter, based on the data in the buffer specified by the infoData parameter.
  6818. The type of setting you wish to change is specified in the infoType parameter. The sound input device information selectors are listed in “Sound Input Device Information Selectors” beginning on page 3-18.
  6819. SPECIAL CONSIDERATIONS
  6820. Because the SPBSetDeviceInfo function might move memory, you should not call it at interrupt time. Check the selector description of the selector you want to use to see if it moves memory before calling the SPBGetDeviceInfo function. Most of the selectors do not move memory and are therefore safe to use at interrupt time.
  6821. ASSEMBLY-LANGUAGE INFORMATION
  6822. The trap macro and routine selector for the SPBSetDeviceInfo function are
  6823. Trap macro    Selector    
  6824. _SoundDispatch    $063C0014    
  6825.  
  6826. RESULT CODESnoErr    0    No error    
  6827. permErr    –54    Attempt to open locked file for writing    
  6828. siBadSoundInDevice    –221    Invalid sound input device    
  6829. siDeviceBusyErr    –227    Sound input device is busy    
  6830. siUnknownInfoType    –231    Unknown type of information    
  6831.  
  6832. Constructing Sound Resource and File Headers
  6833.  
  6834. The Sound Input Manager provides two functions, SetupSndHeader and SetupAIFFHeader, to help you set up headers for sound resources and sound files.
  6835. SetupSndHeader
  6836.  
  6837. You can use the SetupSndHeader function to construct a sound resource containing sampled sound that can be passed to the SndPlay function.
  6838. FUNCTION SetupSndHeader (sndHandle: Handle;
  6839.                                     numChannels: Integer;
  6840.                                     sampleRate: Fixed;
  6841.                                     sampleSize: Integer; 
  6842.                                     compressionType: OSType; 
  6843.                                     baseFrequency: Integer; 
  6844.                                     numBytes: LongInt; 
  6845.                                     VAR headerLen: Integer): OSErr;
  6846. sndHandle    A handle to a block of memory that is at least large enough to store the sound resource header information. The handle is not resized in any way upon successful completion of SetupSndHeader. The SetupSndHeader function simply fills the relocatable block specified by this parameter with the header information needed for a format 1 'snd ' resource, including the sound resource header, the list of sound commands, and a sampled sound header. It is your application’s responsibility to append the desired sampled-sound data.
  6847. numChannels
  6848. The number of channels for the sound; one channel is equivalent to monaural sound and two channels are equivalent to stereo sound.
  6849. sampleRate
  6850. The rate at which the sound was recorded. The sample rate is declared as a Fixed data type. In order to accommodate sample rates greater than 32 kHz, the most significant bit is not treated as a sign bit; instead, that bit is interpreted as having the value 32,768.
  6851. sampleSize
  6852. The sample size for the original sound (that is, bits per sample).
  6853. compressionType
  6854. The compression type for the sound ('NONE', 'MAC3', 'MAC6', or other third-party types).
  6855. baseFrequency
  6856. The base frequency for the sound, expressed as a MIDI note value.
  6857. numBytes    The number of bytes of audio data that are to be stored in the handle. (This value is not necessarily the same as the number of samples in the sound.)
  6858. headerLen    On exit, the size (in bytes) of the 'snd ' resource header that is created. In no case will this length exceed 100 bytes. This field allows you to put the audio data right after the header in the relocatable block specified by the sndHandle parameter. The value returned depends on the type of sound header created.
  6859. DESCRIPTION
  6860. The SetupSndHeader function creates a format 1 'snd ' resource for a sampled sound. The resource contains a sound resource header that links the sound to the sampled synthesizer, a single sound command (a bufferCmd command to play the accompanying data), and a sampled sound header. You can use SetupSndHeader to construct a sampled sound header that can be passed to the Sound Manager’s SndPlay function or stored as an 'snd ' resource. After calling the SetupSndHeader function, your application should place the sampled-sound data directly after the sampled sound header so that, in essence, the sampled sound header’s final field contains the sound data.
  6861. The sampled sound is in one of three formats depending on several of the parameters passed. Table 3-1 shows how SetupSndHeader determines what kind of sound header to create. 
  6862. Table 3-1    The sampled sound header format used by SetupSndHeader
  6863. compressionType    numChannels    sampleSize    Sampled sound header format    
  6864. 'NONE'    1    8    SoundHeader    
  6865. 'NONE'    1    16    ExtSoundHeader    
  6866. 'NONE'    2    any    ExtSoundHeader    
  6867.  not 'NONE'    any    any    CmpSoundHeader    
  6868.  
  6869. A good way to use this function is to create a handle in which you want to store a sampled sound, then call SetupSndHeader with the numBytes parameter set to 0 to see how much room the header for that sound will occupy and hence where to append the audio data. Then record the data into the handle and call SetupSndHeader again with numBytes set to the correct amount of sound data recorded. The handle filled out in this way can be passed to SndPlay to play the sound.
  6870. SPECIAL CONSIDERATIONS
  6871. You cannot call the SetupSndHeader function at interrupt time.
  6872. ASSEMBLY-LANGUAGE INFORMATION
  6873. The trap macro and routine selector for the SetupSndHeader function are
  6874. Trap macro    Selector    
  6875. _SoundDispatch    $0D480014    
  6876.  
  6877. RESULT CODES
  6878. noErr    0    No error    
  6879. siInvalidCompression    –223    Invalid compression type    
  6880.  
  6881. SEE ALSO
  6882. For an example that uses the SetupSndHeader function to set up a sound header before recording, see Listing 3-1 on page 3-7.
  6883. SetupAIFFHeader
  6884.  
  6885. You can use the SetupAIFFHeader function to set up a file that can subsequently be played by SndStartFilePlay.
  6886. FUNCTION SetupAIFFHeader (fRefNum: Integer; 
  6887.                                     numChannels: Integer;
  6888.                                      sampleRate: Fixed; 
  6889.                                     sampleSize: Integer;
  6890.                                     compressionType: OSType; 
  6891.                                     numBytes: LongInt;
  6892.                                      numFrames: LongInt): OSErr;
  6893. fRefNum    A file reference number of a file that is open for writing.
  6894. numChannels
  6895. The number of channels for the sound; one channel is equivalent to monaural sound and two channels are equivalent to stereo sound.
  6896. sampleRate
  6897. The rate at which the sound was recorded. The sample rate is declared as a Fixed data type. In order to accommodate sample rates greater than 32 kHz, the most significant bit is not treated as a sign bit; instead, that bit is interpreted as having the value 32,768. 
  6898. sampleSize
  6899. The sample size for the original sound (that is, bits per sample).
  6900. compressionType
  6901. The compression type for the sound ('NONE', 'MAC3', 'MAC6', or other third-party types).
  6902. numBytes    The number of bytes of audio data that are to be stored in the Common Chunk of the AIFF or AIFF-C file.
  6903. numFrames    The number of sample frames for the sample sound. If you are using a compression type defined by Apple, you can pass 0 in this field and the appropriate value for this field will be computed automatically.
  6904. DESCRIPTION
  6905. The SetupAIFFHeader function creates an AIFF or AIFF-C file header, depending on the parameters passed to it:
  6906. n    Uncompressed sounds of any type are stored in AIFF format (that is, the compressionType parameter is 'NONE').
  6907. n    Compressed sounds of any type are stored in AIFF-C format (that is, the compressionType parameter is different from 'NONE').
  6908. Note
  6909. The SetupAIFFHeader function might format a sound file as an AIFF file even if the File Manager file type of a file is 'AIFC'. The Sound Manager will still play such files correctly.u
  6910. The AIFF header information is written starting at the current file position of the file specified by the fRefNum parameter, and the file position is left at the end of the header upon completion. The SetupAIFFHeader function creates a Form Chunk, a Format Version Chunk, a Common Chunk, and a Sound Data chunk, but it does not put any sound data at the end of the Sound Data Chunk.
  6911. A good way to use this routine is to create a file that you want to store a sound in, then call SetupAIFFHeader with numBytes set to 0 to position the file to be ready to write the audio data. Then record the data to the file, set the file position to the beginning of the file, and call SetupAIFFHeader again with numBytes set to the correct amount of sound data recorded. The file created in this way can be passed to the SndStartFilePlay function to play the sound.
  6912. SPECIAL CONSIDERATIONS
  6913. If recording produces an odd number of bytes of sound data, you must add a pad byte to make the total number of bytes even.
  6914. Because the SetupAIFFHeader function moves memory, you should not call it at interrupt time.
  6915. ASSEMBLY-LANGUAGE INFORMATION
  6916. The trap macro and routine selector for the SetupAIFFHeader function are
  6917. Trap macro    Selector    
  6918. _SoundDispatch    $0B4C0014    
  6919.  
  6920. RESULT CODESnoErr    0    No error    
  6921. siInvalidCompression    –223    Invalid compression type    
  6922.  
  6923. Registering Sound Input Devices
  6924.  
  6925. Sound input device drivers must call the SPBSignInDevice function to register with the Sound Input Manager before they can use its sound input services. You might call this routine at system startup time from within an extension to install a sound input device driver. Your application can generate a list of registered sound input devices by using the SPBGetIndexedDevice function. You can cancel the registration of your driver, thus removing it from the Sound control panel and making it inaccessible, by calling the SPBSignOutDevice function.
  6926. SPBSignInDevice
  6927.  
  6928. You can register a sound input device by calling the SPBSignInDevice function.
  6929. FUNCTION SPBSignInDevice (deviceRefNum: Integer; 
  6930.                                     deviceName: Str255): OSErr;
  6931. deviceRefNum
  6932. The device driver reference number of the sound input device to register with the Sound Input Manager.
  6933. deviceName
  6934. The device’s name as it is to appear to the user in the Sound In control panel (which is not the name of the driver used by the Device Manager).
  6935. DESCRIPTION
  6936. The SPBSignInDevice function registers with the Sound Input Manager the device whose driver reference number is deviceRefNum.
  6937. The deviceName parameter specifies this device’s name as it is to appear to the user in the Sound In control panel (which is not the name of the driver itself). Accordingly, the name should be as descriptive as possible. You should call SPBSignInDevice after you have already opened your driver by calling normal Device Manager routines.
  6938. SPECIAL CONSIDERATIONS
  6939. Because the SPBSignInDevice function moves or purges memory, you should not call it at interrupt time. You can, however, call it at system startup time.
  6940. ASSEMBLY-LANGUAGE INFORMATION
  6941. The trap macro and routine selector for the SPBSignInDevice function are
  6942. Trap macro    Selector    
  6943. _SoundDispatch    $030C0014    
  6944.  
  6945. RESULT CODESnoErr    0    No error    
  6946. siBadSoundInDevice    –221    Invalid sound input device    
  6947.  
  6948. SPBGetIndexedDevice
  6949.  
  6950. You can use the SPBGetIndexedDevice function to help generate a list of sound input devices.
  6951. FUNCTION SPBGetIndexedDevice (count: Integer; 
  6952.                                             VAR deviceName: Str255;
  6953.                                             VAR deviceIconHandle: Handle):
  6954.                                             OSErr;
  6955. count    The index number of the sound input device you wish to obtain information about.
  6956. deviceName
  6957. On exit, the name of the sound input device specified by the count parameter.
  6958. deviceIconHandle
  6959. On exit, a handle to the icon of the sound input device specified by the count parameter. The memory for this icon is allocated automatically, but your application must dispose of it.
  6960. DESCRIPTION
  6961. The SPBGetIndexedDevice function returns the name and icon of the device whose index is specified in the count parameter. Your application can create a list of sound input devices by calling this function with a count starting at 1 and incrementing it by 1 until the function returns siBadSoundInDevice.
  6962. Because the Sound In control panel allows the user to select a sound input device, most applications should not use this function. Your application might need to use this function if it allows the user to record from more than one sound input device at once.
  6963. SPECIAL CONSIDERATIONS
  6964. Because the SPBGetIndexedDevice function allocates memory, you should not call it at interrupt time.
  6965. ASSEMBLY-LANGUAGE INFORMATION
  6966. The trap macro and routine selector for the SPBGetIndexedDevice function are
  6967. Trap macro    Selector    
  6968. _SoundDispatch    $05140014    
  6969.  
  6970. RESULT CODESnoErr    0    No error    
  6971. siBadSoundInDevice    –221    Invalid sound input device    
  6972.  
  6973. SPBSignOutDevice
  6974.  
  6975. You can use the SPBSignOutDevice function to cancel the registration of a device you have previously registered with the SPBSignInDevice function.
  6976. FUNCTION SPBSignOutDevice (deviceRefNum: Integer): OSErr;
  6977. deviceRefNum
  6978. The driver reference number of the device you wish to sign out.
  6979. DESCRIPTION
  6980. The SPBSignOutDevice function cancels the registration of the device whose driver reference number is deviceRefNum; the device is unregistered from the Sound Input Manager’s list of available sound input devices and no longer appears in the Sound In control panel.
  6981. Ordinarily, you should not need to use the SPBSignOutDevice function. You might use it if your device driver detects that a sound input device is not functioning correctly or has been disconnected.
  6982. SPECIAL CONSIDERATIONS
  6983. Because the SPBSignOutDevice function moves or purges memory, you should not call it at interrupt time.
  6984. ASSEMBLY-LANGUAGE INFORMATION
  6985. The trap macro and routine selector for the SPBSignOutDevice function are
  6986. Trap macro    Selector    
  6987. _SoundDispatch    $01100014    
  6988.  
  6989. RESULT CODESnoErr    0    No error    
  6990. siBadSoundInDevice    –221    Invalid sound input device    
  6991. siDeviceBusyErr    –227    Sound input device is busy    
  6992.  
  6993. Converting Between Milliseconds and Bytes
  6994.  
  6995. The Sound Input Manager provides two routines that allow you to convert between millisecond and byte recording values.
  6996. SPBMilliSecondsToBytes
  6997.  
  6998. You can use the SPBMilliSecondsToBytes function to determine how many bytes a recording of a certain duration will use.
  6999. FUNCTION SPBMilliSecondsToBytes (inRefNum: LongInt; 
  7000.                                         VAR milliseconds: LongInt): OSErr;
  7001. inRefNum    The device reference number of the sound input device, as obtained from the SPBOpenDevice function.
  7002. milliseconds
  7003. On entry, the duration of the recording in milliseconds. On exit, the number of bytes that sampled-sound data would occupy for a recording of the specified duration on the device specified by the inRefNum parameter.
  7004. DESCRIPTION
  7005. The SPBMilliSecondsToBytes function reports how many bytes are required to store a recording of duration milliseconds, given the input device’s current sample rate, sample size, number of channels, and compression factor.
  7006. SPECIAL CONSIDERATIONS
  7007. You can call the SPBMilliSecondsToBytes function at interrupt time.
  7008. ASSEMBLY-LANGUAGE INFORMATION
  7009. The trap macro and routine selector for the SPBMilliSecondsToBytes function are
  7010. Trap macro    Selector    
  7011. _SoundDispatch    $04400014    
  7012.  
  7013. RESULT CODESnoErr    0    No error    
  7014. siBadSoundInDevice    –221    Invalid sound input device    
  7015.  
  7016. SPBBytesToMilliSeconds
  7017.  
  7018. You can use the SPBBytesToMilliSeconds function to determine the maximum duration of a recording that can fit in a buffer of a certain size.
  7019. FUNCTION SPBBytesToMilliSeconds (inRefNum: LongInt; 
  7020.                                             VAR byteCount: LongInt): OSErr;
  7021. inRefNum    The device reference number of the sound input device, as obtained from the SPBOpenDevice function.
  7022. byteCount    On entry, a value in bytes. On exit, the number of milliseconds of recording on the device specified by the inRefNum parameter that would be necessary to fill a buffer of such a size.
  7023. DESCRIPTION
  7024. The SPBBytesToMilliSeconds function reports how many milliseconds of audio data can be recorded in a buffer that is byteCount bytes long, given the input device’s current sample rate, sample size, number of channels, and compression factor.
  7025. SPECIAL CONSIDERATIONS
  7026. You can call the SPBBytesToMilliSeconds function at interrupt time.
  7027. ASSEMBLY-LANGUAGE INFORMATION
  7028. The trap macro and routine selector for the SPBBytesToMilliSeconds function are
  7029. Trap macro    Selector    
  7030. _SoundDispatch    $04440014    
  7031.  
  7032. RESULT CODESnoErr    0    No error    
  7033. siBadSoundInDevice    –221    Invalid sound input device    
  7034.  
  7035. Obtaining Information
  7036.  
  7037. The SPBVersion function allows you to determine the version of the Sound Input Manager.
  7038. SPBVersion
  7039.  
  7040. You can use the SPBVersion function to determine the version of the sound input tools available on a machine.
  7041. FUNCTION SPBVersion: NumVersion;
  7042. DESCRIPTION
  7043. The SPBVersion function returns a version number that contains the same information as in the first 4 bytes of a 'vers' resource or a NumVersion data type. For a description of the version record, see the chapter “Sound Manager” in this book.
  7044. SPECIAL CONSIDERATIONS
  7045. You can call the SPBVersion function at interrupt time.
  7046. ASSEMBLY-LANGUAGE INFORMATION
  7047. The trap macro and routine selector for the SPBVersion function are
  7048. Trap macro    Selector    
  7049. _SoundDispatch    $00000014    
  7050.  
  7051. SEE ALSO
  7052. For a complete discussion of 'vers' resources, see the chapter “Finder Interface” in Inside Macintosh: Macintosh Toolbox Essentials.
  7053. Application-Defined Routines
  7054.  
  7055. This section describes the routines that your application or device driver might need to define. Your application can define a sound input completion routine to perform an action when recording finishes, and your application can define a sound input interrupt routine to manipulate sound data during recording.
  7056. Sound Input Completion Routines
  7057.  
  7058. You can specify a sound input completion routine in the completionRoutine field of a sound input parameter block that your application uses to initiate asynchronous recording directly from a device.
  7059. MySICompletionRoutine
  7060.  
  7061. A sound input completion routine has the following syntax:
  7062. PROCEDURE MySICompletionRoutine (inParamPtr: SPBPtr);
  7063. inParamPtr
  7064. A pointer to the sound input parameter block that was used to initiate an asynchronous recording.
  7065. DESCRIPTION
  7066. The Sound Input Manager executes your sound input completion routine after recording terminates either because your application has called the SPBStopRecording function or because the prescribed limit is reached. The completion routine is called only for asynchronous recording.
  7067. A common use of a sound input completion routine is to set a global variable that alerts the application that it should dispose of a sound input parameter block that it had allocated for an asynchronous sound recording.
  7068. SPECIAL CONSIDERATIONS
  7069. Because a sound input completion routine is executed at interrupt time, it should not allocate, move, or purge memory (either directly or indirectly) and should not depend on the validity of handles to unlocked blocks.
  7070. If your sound input completion routine accesses your application’s global variables, it must ensure that the A5 register contains the address of the boundary between the application global variables and the application parameters. Your application can pass the value of the A5 register to the sound input completion routine in the userLong field of the sound input parameter block. For more information on ensuring the validity of the A5 register, see the chapter “Memory Management Utilities” in Inside Macintosh: Memory.
  7071. Your sound input completion routine can determine whether an error occurred during recording by examining the error field of the sound input parameter block specified by inParamPtr. Your sound input completion routine can change the value of that field to alert the application that some other error has occurred.
  7072. ASSEMBLY-LANGUAGE INFORMATION
  7073. Because a sound input completion routine is called at interrupt time, it must preserve all registers other than A0–A1 and D0–D2.
  7074. RESULT CODESnoErr    0    No error    
  7075. abortErr    –27    Asynchronous recording was cancelled    
  7076. siNoSoundInHardware    –220    No sound input hardware available    
  7077. siBadSoundInDevice    –221    Invalid sound input device    
  7078. siNoBufferSpecified    –222    No buffer specified    
  7079. siDeviceBusyErr    –227    Sound input device is busy    
  7080.  
  7081. Sound Input Interrupt Routines
  7082.  
  7083. You can specify a sound input interrupt routine in the interruptRoutine field of the sound input parameter block that your application uses to initiate asynchronous recording directly from a device. Because the SPBRecordToFile function uses sound input interrupt routines to enable it to record sound data to disk during recording, you can use sound input interrupt routines only with the SPBRecord function.
  7084. MySIInterruptRoutine
  7085.  
  7086. A sound input interrupt routine has the following syntax:
  7087. PROCEDURE MySIInterruptRoutine;
  7088. DESCRIPTION
  7089. A sound input device driver executes the sound input interrupt routine associated with an asynchronous sound recording whenever the driver’s internal buffers are full. The internal buffers contain raw samples taken directly from the input device. The interrupt routine can thus modify the samples in the buffer in any way it requires. After your sound input interrupt routine finishes processing the data, the sound input device driver compresses the data (if compression is enabled) and copies the data into your application’s buffer.
  7090. SPECIAL CONSIDERATIONS
  7091. If your sound input interrupt routine accesses your application’s global variables, it must ensure that the A5 register contains the address of the boundary between the application global variables and the application parameters. Your application can pass the value of the A5 register to the sound input interrupt routine in the userLong field of the sound input parameter block. For more information on ensuring the validity of the A5 register, see the chapter “Memory Management Utilities” in Inside Macintosh: Memory.
  7092. ASSEMBLY-LANGUAGE INFORMATION
  7093. Sound input interrupt routines are sometimes written in assembly language to maximize real-time performance in recording sound. On entry, registers are set up as follows: Registers on entry        
  7094. A0    Address of the sound parameter block passed to SPBRecord    
  7095. A1    Address of the start of the sample buffer    
  7096. D0    Peak amplitude for sample buffer if metering is on    
  7097. D1    Size of the sample buffer in bytes    
  7098.  
  7099. If you write a sound input interrupt routine in a high-level language like Pascal or C, you might need to write inline code to copy variables from the registers into local variables that your application defines.
  7100. Because a sound input interrupt routine is called at interrupt time, it must preserve all registers.
  7101.  
  7102.  
  7103. Summary of the Sound Input Manager
  7104.  
  7105. Pascal Summary
  7106.  
  7107. Constants
  7108.  
  7109. CONST
  7110.     gestaltSoundAttr                                    = 'snd ';            {sound attributes selector}
  7111.     {Gestalt response bit flags related to sound input}
  7112.     gestaltSoundIOMgrPresent                                    = 3;            {sound input routines available}
  7113.     gestaltBuiltInSoundInput                                    = 4;            {built-in input hw available}
  7114.     gestaltHasSoundInputDevice                                    = 5;            {sound input device available}
  7115.     gestaltPlayAndRecord                                    = 6;            {built-in hw can play while recording}
  7116.     gestalt16BitSoundIO                                     = 7;            {built-in hw can handle 16-bit data}
  7117.     gestaltStereoInput                                     = 8;            {built-in hw can record stereo sounds}
  7118.     gestaltLineLevelInput                                     = 9;            {built-in input hw needs line level}
  7119.     {available information selectors for sound input device drivers}
  7120.     siActiveChannels                                = 'chac';                {channels active}
  7121.     siActiveLevels                                = 'lmac';                {levels active}
  7122.     siAGCOnOff                                = 'agc ';                {automatic gain control state}
  7123.     siAsync                                = 'asyn';                {asynchronous capability}
  7124.     siChannelAvailable                                = 'chav';                {number of channels available}
  7125.     siCompressionAvailable                                = 'cmav';                {compression types available}
  7126.     siCompressionFactor                                = 'cmfa';                {current compression factor}
  7127.     siCompressionHeader                                = 'cmhd';                {return compression header}
  7128.     siCompressionNames                                = 'cnam';                {return compression type names}
  7129.     siCompressionType                                = 'comp';                {current compression type}
  7130.     siContinuous                                = 'cont';                {continuous recording}
  7131.     siDeviceBufferInfo                                = 'dbin';                {size of interrupt buffer}
  7132.     siDeviceConnected                                = 'dcon';                {input device connection status}
  7133.     siDeviceIcon                                = 'icon';                {input device icon}
  7134.     siDeviceName                                = 'name';                {input device name}
  7135.     siInputGain                                = 'gain';                {input gain level}
  7136.     siInputSource                                = 'sour';                {input source selector}
  7137.     siInputSourceNames                                = 'snam';                {input source names}
  7138.     siLevelMeterOnOff                                = 'lmet';                {level meter state}
  7139.     siNumberChannels                                = 'chan';                {current number of channels}
  7140.     siOptionsDialog                                = 'optd';                {display options dialog box}
  7141.     siPlayThruOnOff                                = 'plth';                {play-through state}
  7142.     siRecordingQuality                                = 'qual';                {recording quality}
  7143.     siSampleRate                                = 'srat';                {current sample rate}
  7144.     siSampleRateAvailable                                = 'srav';                {sample rates available}
  7145.     siSampleSize                                = 'ssiz';                {current sample size}
  7146.     siSampleSizeAvailable                                = 'ssav';                {sample sizes available}
  7147.     siStereoInputGain                                = 'sgai';                {stereo input gain level}
  7148.     siTwosComplementOnOff                                = 'twos';                {two's complement state}
  7149.     siVoxRecordInfo                                = 'voxr';                {VOX record parameters}
  7150.     siVoxStopInfo                                = 'voxs';                {VOX stop parameters}
  7151.     {internal information selectors for sound input device drivers}
  7152.     siCloseDriver                                = 'clos';                {release driver}
  7153.     siInitializeDriver                                = 'init';                {initialize driver}
  7154.     siPauseRecording                                = 'paus';                {pause recording}
  7155.     siUserInterruptProc                                = 'user';                {set sound input interrupt routine}
  7156.     {sound-recording qualities}
  7157.     siBestQuality                                = 'best';                {the best quality available}
  7158.     siBetterQuality                                = 'betr';                {a quality better than good}
  7159.     siGoodQuality                                = 'good';                {a good quality}
  7160.     {sound input device permissions}
  7161.     siReadPermission                                = 0;                {open device for reading}
  7162.     siWritePermission                                = 1;                {open device for reading/writing}
  7163.     {device-connection states}
  7164.     siDeviceIsConnected                                = 1;                {device is connected and ready}
  7165.     siDeviceNotConnected                                = 0;                {device is not connected}
  7166.     siDontKnowIfConnected                                = -1;                {can't tell if device is connected}
  7167. Data Types
  7168.  
  7169. Sound Input Parameter Block
  7170. TYPE SPB =
  7171. RECORD
  7172.     inRefNum:                            LongInt;                {reference number of input device}
  7173.     count:                            LongInt;                {number of bytes to record}
  7174.     milliseconds:                            LongInt;                {number of milliseconds to record}
  7175.     bufferLength:                            LongInt;                {length of buffer to record into}
  7176.     bufferPtr:                            Ptr;                {pointer to buffer to record into}
  7177.     completionRoutine:                            ProcPtr;                {pointer to a completion routine}
  7178.     interruptRoutine:                            ProcPtr;                {pointer to an interrupt routine}
  7179.     userLong:                            LongInt;                {for application's use}
  7180.     error:                            OSErr;                {error returned after recording}
  7181.     unused1:                            LongInt;                {reserved}
  7182. END;
  7183. SPBPtr = ^SPB;
  7184. Sound Input Manager Routines
  7185.  
  7186. Recording Sounds
  7187. FUNCTION SndRecord    (filterProc: ProcPtr; corner: Point; 
  7188. quality: OSType; VAR sndHandle: Handle): OSErr;
  7189. FUNCTION SndRecordToFile    (filterProc: ProcPtr; corner: Point; 
  7190. quality: OSType; fRefNum: Integer): OSErr;
  7191. Opening and Closing Sound Input Devices
  7192. FUNCTION SPBOpenDevice    (deviceName: Str255; permission: Integer; 
  7193. VAR inRefNum: LongInt): OSErr;
  7194. FUNCTION SPBCloseDevice    (inRefNum: LongInt): OSErr;
  7195. Recording Sounds Directly From Sound Input Devices
  7196. FUNCTION SPBRecord    (inParamPtr: SPBPtr; asynchFlag: Boolean): OSErr;
  7197. FUNCTION SPBRecordToFile    (fRefNum: Integer; inParamPtr: SPBPtr; asynchFlag: Boolean): OSErr;
  7198. FUNCTION SPBPauseRecording    (inRefNum: LongInt): OSErr;
  7199. FUNCTION SPBResumeRecording
  7200. (inRefNum: LongInt): OSErr;
  7201. FUNCTION SPBStopRecording    (inRefNum: LongInt): OSErr;
  7202. FUNCTION SPBGetRecordingStatus
  7203. (inRefNum: LongInt; 
  7204. VAR recordingStatus: Integer; 
  7205. VAR meterLevel: Integer; 
  7206. VAR totalSamplesToRecord: LongInt; 
  7207. VAR numberOfSamplesRecorded: LongInt; 
  7208. VAR totalMsecsToRecord: LongInt; 
  7209. VAR numberOfMsecsRecorded: LongInt): OSErr;
  7210. Manipulating Device Settings
  7211. FUNCTION SPBGetDeviceInfo    (inRefNum: LongInt; infoType: OSType; 
  7212. infoData: Ptr): OSErr;
  7213. FUNCTION SPBSetDeviceInfo    (inRefNum: LongInt; infoType: OSType; 
  7214. infoData: Ptr): OSErr;
  7215. Constructing Sound Resource and File Headers
  7216. FUNCTION SetupSndHeader    (sndHandle: Handle; numChannels: Integer; sampleRate: Fixed; sampleSize: Integer; compressionType: OSType; 
  7217. baseFrequency: Integer; numBytes: LongInt; 
  7218. VAR headerLen: Integer): OSErr;
  7219. FUNCTION SetupAIFFHeader    (fRefNum: Integer; numChannels: Integer; sampleRate: Fixed; sampleSize: Integer; compressionType: OSType; numBytes: LongInt; numFrames: LongInt): OSErr;
  7220. Registering Sound Input Devices
  7221. FUNCTION SPBSignInDevice    (deviceRefNum: Integer; deviceName: Str255): OSErr;
  7222. FUNCTION SPBGetIndexedDevice
  7223. (count: Integer; VAR deviceName: Str255; 
  7224. VAR deviceIconHandle: Handle): OSErr;
  7225. FUNCTION SPBSignOutDevice    (deviceRefNum: Integer): OSErr;
  7226. Converting Between Milliseconds and Bytes
  7227. FUNCTION SPBMilliSecondsToBytes
  7228. (inRefNum: LongInt; VAR milliseconds: LongInt): OSErr;
  7229. FUNCTION SPBBytesToMilliSeconds
  7230. (inRefNum: LongInt; VAR byteCount: LongInt): OSErr;
  7231. Obtaining Information
  7232. FUNCTION SPBVersion    : NumVersion;
  7233. Application-Defined Routines
  7234.  
  7235. PROCEDURE MySICompletionRoutine
  7236. (inParamPtr: SPBPtr);
  7237. PROCEDURE MySIInterruptRoutine;
  7238. C Summary
  7239.  
  7240. Constants
  7241.  
  7242. #define gestaltSoundAttr                                     'snd '            /*sound attributes selector*/
  7243. enum {
  7244.     /*Gestalt response bit flags related to sound input*/
  7245.     gestaltSoundIOMgrPresent                                    = 3,        /*sound input routines available*/
  7246.     gestaltBuiltInSoundInput                                    = 4,        /*built-in input hw available*/
  7247.     gestaltHasSoundInputDevice                                    = 5,        /*sound input device available*/
  7248.     gestaltPlayAndRecord                                    = 6,        /*built-in hw can play while recording*/
  7249.     gestalt16BitSoundIO                                     = 7,        /*built-in hw can handle 16-bit data*/
  7250.     gestaltStereoInput                                     = 8,        /*built-in hw can record stereo sounds*/
  7251.     gestaltLineLevelInput                                     = 9        /*built-in input hw needs line level*/
  7252. };
  7253. /*available information selectors for sound input device drivers*/
  7254. #define siActiveChannels                                        'chac'            /*channels active*/
  7255. #define siActiveLevels                                        'lmac'            /*levels active*/
  7256. #define siAGCOnOff                                        'agc '            /*automatic gain control state*/
  7257. #define siAsync                                        'asyn'            /*asynchronous capability*/
  7258. #define siChannelAvailable                                        'chav'            /*number of channels available*/
  7259. #define siCompressionAvailable                                        'cmav'            /*compression types available*/
  7260. #define siCompressionFactor                                        'cmfa'            /*current compression factor*/
  7261. #define siCompressionHeader                                        'cmhd'            /*return compression header*/
  7262. #define siCompressionNames                                        'cnam'            /*return compression type names*/
  7263. #define siCompressionType                                        'comp'            /*current compression type*/
  7264. #define siContinuous                                        'cont'            /*continuous recording*/
  7265. #define siDeviceBufferInfo                                        'dbin'            /*size of interrupt buffer*/
  7266. #define siDeviceConnected                                        'dcon'            /*input device connection status*/
  7267. #define siDeviceIcon                                        'icon'            /*input device icon*/
  7268. #define siDeviceName                                        'name'            /*input device name*/
  7269. #define siInputGain                                        'gain'            /*input gain level*/
  7270. #define siInputSource                                        'sour'            /*input source selector*/
  7271. #define siInputSourceNames                                        'snam'            /*input source names*/
  7272. #define siLevelMeterOnOff                                        'lmet'            /*level meter state*/
  7273. #define siNumberChannels                                        'chan'            /*current number of channels*/
  7274. #define siOptionsDialog                                        'optd'            /*display options dialog box*/
  7275. #define siPlayThruOnOff                                        'plth'            /*play-through state*/
  7276. #define siRecordingQuality                                        'qual'            /*recording quality*/
  7277. #define siSampleRate                                        'srat'            /*current sample rate*/
  7278. #define siSampleRateAvailable                                        'srav'            /*sample rates available*/
  7279. #define siSampleSize                                        'ssiz'            /*current sample size*/
  7280. #define siSampleSizeAvailable                                        'ssav'            /*sample sizes available*/
  7281. #define siStereoInputGain                                        'sgai'            /*stereo input gain level*/
  7282. #define siTwosComplementOnOff                                        'twos'            /*two's complement state*/
  7283. #define siVoxRecordInfo                                        'voxr'            /*VOX record parameters*/
  7284. #define siVoxStopInfo                                        'voxs'            /*VOX stop parameters*/
  7285. /*internal information selectors for sound input device drivers*/
  7286. #define siCloseDriver                                        'clos'            /*release driver*/
  7287. #define siInitializeDriver                                        'init'            /*initialize driver*/
  7288. #define siPauseRecording                                        'paus'            /*pause recording*/
  7289. #define siUserInterruptProc                                        'user'            /*set sound input interrupt routine*/
  7290. /*sound-recording qualities*/
  7291. #define siBestQuality                                        'best'            /*the best quality available*/
  7292. #define siBetterQuality                                        'betr'            /*a quality better than good*/
  7293. #define siGoodQuality                                        'good'            /*a good quality*/
  7294. /*sound input device permissions*/
  7295. enum {
  7296.     siReadPermission                                    = 0,            /*open device for reading*/
  7297.     siWritePermission                                    = 1            /*open device for reading/writing*/
  7298. };
  7299. /*device-connection states*/
  7300. enum {
  7301.     siDeviceIsConnected                                    = 1,            /*device is connected and ready*/
  7302.     siDeviceNotConnected                                    = 0,            /*device is not connected*/
  7303.     siDontKnowIfConnected                                    = -1            /*can't tell if device is connected*/
  7304. };
  7305. Data Types
  7306.  
  7307. Sound Input Parameter Block
  7308. struct SPB {
  7309.     long                            inRefNum;                    /*reference number of input device*/
  7310.     unsigned long                            count;                    /*number of bytes to record*/
  7311.     unsigned long                            milliseconds;                    /*number of milliseconds to record*/
  7312.     unsigned long                            bufferLength;                    /*length of buffer to record into*/
  7313.     Ptr                            bufferPtr;                    /*pointer to buffer to record into*/
  7314.     ProcPtr                            completionRoutine;
  7315.                                                     /*pointer to a completion routine*/
  7316.     ProcPtr                            interruptRoutine;
  7317.                                                     /*pointer to an interrupt routine*/
  7318.     long                            userLong;                    /*for application's use*/
  7319.     OSErr                            error;                    /*error returned after recording*/
  7320.     long                            unused1;                    /*reserved*/
  7321. };
  7322. typedef struct SPB SPB;
  7323. typedef SPB *SPBPtr;
  7324. Sound Input Manager Routines
  7325.  
  7326. Recording Sounds
  7327. pascal OSErr SndRecord    (ModalFilterProcPtr filterProc, Point corner,
  7328. OSType quality, Handle *sndHandle);
  7329. pascal OSErr SndRecordToFile
  7330. (ModalFilterProcPtr filterProc, Point corner,
  7331. OSType quality, short fRefNum);
  7332. Opening and Closing Sound Input Devices
  7333. pascal OSErr SPBOpenDevice    (ConstStr255Param deviceName, short permission,
  7334. long *inRefNum);
  7335. pascal OSErr SPBCloseDevice
  7336. (long inRefNum);
  7337. Recording Sounds Directly From Sound Input Devices
  7338. pascal OSErr SPBRecord    (SPBPtr inParamPtr, Boolean asynchFlag);
  7339. pascal OSErr SPBRecordToFile
  7340. (short fRefNum, SPBPtr inParamPtr, 
  7341. Boolean asynchFlag);
  7342. pascal OSErr SPBPauseRecording
  7343. (long inRefNum);
  7344. pascal OSErr SPBResumeRecording
  7345. (long inRefNum);
  7346. pascal OSErr SPBStopRecording
  7347. (long inRefNum);
  7348. pascal OSErr SPBGetRecordingStatus
  7349. (long inRefNum, short *recordingStatus, 
  7350. short *meterLevel, 
  7351. unsigned long *totalSamplesToRecord, 
  7352. unsigned long *numberOfSamplesRecorded, 
  7353. unsigned long *totalMsecsToRecord, 
  7354. unsigned long *numberOfMsecsRecorded);
  7355. Manipulating Device Settings
  7356. pascal OSErr SPBGetDeviceInfo
  7357. (long inRefNum, OSType infoType, 
  7358. char *infoData);
  7359. pascal OSErr SPBSetDeviceInfo
  7360. (long inRefNum, OSType infoType, 
  7361. char *infoData);
  7362. Constructing Sound Resource and File Headers
  7363. pascal OSErr SetupSndHeader
  7364. (Handle sndHandle, short numChannels, 
  7365. Fixed sampleRate, short sampleSize, 
  7366. OSType compressionType, short baseFrequency, 
  7367. unsigned long numBytes, short *headerLen);
  7368. pascal OSErr SetupAIFFHeader
  7369. (short fRefNum, short numChannels, 
  7370. Fixed sampleRate, short sampleSize, 
  7371. OSType compressionType,
  7372. unsigned long numBytes, 
  7373. unsigned long numFrames);
  7374. Registering Sound Input Devices
  7375. pascal OSErr SPBSignInDevice
  7376. (short deviceRefNum, 
  7377. ConstStr255Param deviceName);
  7378. pascal OSErr SPBGetIndexedDevice
  7379. (short count, Str255 deviceName, 
  7380. Handle *deviceIconHandle);
  7381. pascal OSErr SPBSignOutDevice
  7382. (short deviceRefNum);
  7383. Converting Between Milliseconds and Bytes
  7384. pascal OSErr SPBMilliSecondsToBytes
  7385. (long inRefNum, long *milliseconds);
  7386. pascal OSErr SPBBytesToMilliSeconds
  7387. (long inRefNum, long *byteCount);
  7388. Obtaining Information
  7389. pascal NumVersion SPBVersion
  7390. (void);
  7391. Application-Defined Routines
  7392.  
  7393. pascal void MySICompletionRoutine
  7394. (SPBPtr inParamPtr);
  7395. pascal void MySIInterruptRoutine
  7396. (void);
  7397. Assembly-Language Summary
  7398.  
  7399. Data Structures
  7400.  
  7401. Sound Input Parameter Block Data Structure0    inRefNum    long    The input device reference number    
  7402. 4    count    long    The number of bytes to record    
  7403. 8    milliseconds    long    The number of milliseconds to record    
  7404. 12    bufferLength    long    The length of the buffer    
  7405. 16    bufferPtr    long    The address of the buffer    
  7406. 20    completionRoutine    long    A pointer to a completion routine    
  7407. 24    interruptRoutine    long    A pointer to an interrupt routine    
  7408. 28    userLong    long    For application’s use    
  7409. 32    error    word    The error value returned after recording    
  7410. 36    unused1    long    Reserved    
  7411.  
  7412. Trap Macros
  7413.  
  7414. Trap Macros Requiring Routine Selectors
  7415. _SoundDispatch
  7416. Selector    Routine    
  7417. $00000014    SPBVersion    
  7418. $01100014    SPBSignOutDevice    
  7419. $021C0014    SPBCloseDevice    
  7420. $02280014    SPBPauseRecording    
  7421. $022C0014    SPBResumeRecording    
  7422. $02300014    SPBStopRecording    
  7423. $030C0014    SPBSignInDevice    
  7424. $03200014    SPBRecord    
  7425. $04240014    SPBRecordToFile    
  7426. $04400014    SPBMillisecondsToBytes    
  7427. $04440014    SPBBytesToMilliseconds    
  7428. $05140014    SPBGetIndexedDevice    
  7429. $05180014    SPBOpenDevice    
  7430. $06380014    SPBGetDeviceInfo    
  7431. $063C0014    SPBSetDeviceInfo    
  7432. $07080014    SndRecordToFile    
  7433. $08040014    SndRecord    
  7434. $0B4C0014    SetupAIFFHeader    
  7435. $0D480014    SetupSndHeader    
  7436. $0E340014    SPBGetRecordingStatus    
  7437.  
  7438. Result CodesnoErr    0    No error    
  7439. abortErr    –27    Asynchronous recording was cancelled    
  7440. permErr    –54    Attempt to open locked file for writing    
  7441. userCanceledErr    –128    User canceled the operation     
  7442. siNoSoundInHardware    –220    No sound input hardware available    
  7443. siBadSoundInDevice    –221    Invalid sound input device    
  7444. siNoBufferSpecified    –222    No buffer specified    
  7445. siInvalidCompression    –223    Invalid compression type    
  7446. siHardDriveTooSlow    –224    Hard drive too slow to record    
  7447. siInvalidSampleRate    –225    Invalid sample rate    
  7448. siInvalidSampleSize    –226    Invalid sample size    
  7449. siDeviceBusyErr    –227    Sound input device is busy    
  7450. siBadDeviceName    –228    Invalid device name    
  7451. siBadRefNum    –229    Invalid reference number    
  7452. siInputDeviceErr    –230    Input device hardware failure    
  7453. siUnknownInfoType    –231    Unknown type of information    
  7454. siUnknownQuality     –232    Unknown quality    
  7455.  
  7456.  
  7457.  
  7458. Listing 4-0
  7459. Table 4-0
  7460. Speech Manager
  7461. Contents
  7462. About the Speech Manager4-4
  7463. Voices4-5
  7464. Speech Attributes4-6
  7465. Speech Channels4-9
  7466. Callback Routines4-10
  7467. Using the Speech Manager4-11
  7468. Checking for Speech Manager Capabilities4-12
  7469. Creating, Using, and Disposing of a Speech Channel4-13
  7470. Working With Different Voices4-14
  7471. Adjusting Speech Attributes4-16
  7472. Pausing Speech4-18
  7473. Implementing Callback Procedures4-19
  7474. Writing Embedded Speech Commands4-23
  7475. Embedded Command Delimiters4-23
  7476. Syntax of Embedded Speech Commands4-24
  7477. Examples of Embedded Speech Commands4-30
  7478. Phonemic Representation of Speech4-32
  7479. Phonemic Symbols4-33
  7480. Prosodic Control Symbols4-34
  7481. Including Pronunciation Dictionaries 4-36
  7482. Speech Manager Reference4-39
  7483. Constants4-39
  7484. Speech Information Selectors4-39
  7485. Data Structures4-45
  7486. Voice Specification Records4-46
  7487. Voice Description Records4-47
  7488. Voice File Information Records4-48
  7489. Speech Status Information Records4-48
  7490. Speech Error Information Records4-49
  7491. Speech Version Information Records4-50
  7492. Phoneme Information Records4-52
  7493. Phoneme Descriptor Records4-53
  7494. Speech Extension Data Records4-53
  7495. Delimiter Information Records4-54
  7496. Speech Manager Routines4-54
  7497. Starting, Stopping, and Pausing Speech4-55
  7498. Obtaining Information About Voices4-63
  7499. Managing Speech Channels4-69
  7500. Obtaining Information About Speech4-71
  7501. Changing Speech Attributes4-73
  7502. Converting Text To Phonemes4-79
  7503. Installing a Pronunciation Dictionary4-80
  7504. Application-Defined Routines4-82
  7505. Text-Done Callback Procedure4-82
  7506. Speech-Done Callback Procedure4-84
  7507. Synchronization Callback Procedure4-85
  7508. Error Callback Procedure4-86
  7509. Phoneme Callback Procedure4-87
  7510. Word Callback Procedure4-88
  7511. Resources4-89
  7512. The Pronunciation Dictionary Resource4-89
  7513. Summary of the Speech Manager4-94
  7514. Pascal Summary4-94
  7515. Constants4-94
  7516. Data Structures4-95
  7517. Speech Manager Routines4-98
  7518. Application-Defined Routines4-100
  7519. C Summary4-100
  7520. Constants4-100
  7521. Data Types4-102
  7522. Speech Manager Routines4-105
  7523. Application-Defined Routines4-106
  7524. Assembly-Language Information4-107
  7525. Data Structures4-107
  7526. Trap Macros4-109
  7527. Result Codes4-110
  7528. Speech Manager
  7529. This chapter describes the Speech Manager, the part of the Macintosh system software that provides a standardized method for Macintosh applications to generate synthesized speech.
  7530. You need to read this chapter if you want your application to be able to generate speech. For example, you may want your application to incorporate the capability to speak its dialog box messages to the user. A word-processing application might use the Speech Manager to implement a command that speaks a selected section of a document to the user. A multimedia application might use the Speech Manager to provide a narration of a QuickTime movie instead of including sampled-sound data on a movie track. Because sound samples can take up large amounts of room on disk, using text in place of sampled sound is extremely efficient.
  7531. If you are developing an application that needs only to generate speech from strings, then the information on speech contained in the chapter “Introduction to Sound on the Macintosh” in this book might be sufficient. If, however, you need to be able to manipulate the speech output or customize it to make it easier for your users to understand, you should read this chapter.
  7532. The Speech Manager is not available in all system software versions. It was introduced with the Macintosh computers with audio visual capabilities in the summer of 1993. It will continue to be incorporated into future versions of system software. You should use the Gestalt function to ensure that the speech services you need are available before calling them. See the discussion in the section “Checking for Speech Manager Capabilities” beginning on page 4-12 for details.
  7533. The Speech Manager and the Sound Manager adopt many of the same metaphors in the processes of sound production and speech generation. You should be aware that the Speech Manager’s approach often differs in subtle but important ways from that of the Sound Manager. Reading the chapter “Sound Manager” in this book might help you to learn to use the Speech Manager, but it is not required.
  7534. Also, while the Speech Manager uses the Sound Manager, your application should not attempt to directly access any Sound Manager data structures used by the Speech Manager. Because the Speech Manager is likely to be a rapidly evolving portion of system software, relying on Speech Manager data structures not explicitly documented in this chapter is likely to pose compatibility problems for your application.
  7535. This chapter begins with an introduction to the speech generation process and then discusses how you can
  7536. n    check for the availability of the Speech Manager
  7537. n    create and dispose of speech channels
  7538. n    generate speech with different voices
  7539. n    obtain information about and change speech channel settings
  7540. n    start and stop speech production
  7541. n    synchronize speech production with other activities by using callback procedures
  7542. n    embed Speech Manager commands within text to make it more understandable
  7543. n    convert text into phonemes and allow the user to enter phonetic text directly
  7544. n    create, install, and manipulate customized pronunciation dictionaries
  7545.  
  7546. About the Speech Manager
  7547.  
  7548. You can use the Speech Manager to incorporate synthesized speech into your application. This section provides an overview and describes the basic concepts of the Speech Manager, and it outlines the process that the Speech Manager uses to convert text into speech. The Speech Manager converts text into sound data, which it passes to the Sound Manager to play through the current sound output device. The Speech Manager’s interaction with the Sound Manager is transparent to your application, so you don’t need to be familiar with the Sound Manager to take advantage of the Speech Manager’s capabilities.
  7549. Figure 4-1 illustrates the speech generation process. Your application can initiate speech generation by passing a string or a buffer of text to the Speech Manager. The Speech Manager is responsible for sending the text to a speech synthesizer, a component that contains executable code that manages all communication between the Speech Manager and the Sound Manager. A synthesizer is usually contained in a resource in a file within the System Folder. A synthesizer is like a speech engine. It uses built-in dictionaries and pronunciation rules to help determine how to pronounce text. You can provide custom pronunciation dictionaries as described in the section “Including Pronunciation Dictionaries” beginning on page 4-36.
  7550. Figure 4-1    The speech generation process
  7551.  
  7552. As Figure 4-1 suggests, the Speech Manager is simply a dispatch mechanism that allows your application to take advantage of the capabilities of whatever speech synthesizers, voices, and hardware are installed. The Speech Manager itself does not do any of the work of converting text into speech; it just provides a convenient programming interface that manages access to speech synthesizers and, indirectly, to the sound hardware. The Speech Manager uses the Component Manager to access whatever speech synthesizers are available and allows applications to take maximum advantage of a computer’s speech facilities without knowing what those facilities are. Because the Speech Manager’s routines work on all voices and synthesizers, you will not need to rewrite your application to take advantage of improvements in speech technology.
  7553. Voices
  7554.  
  7555. Your application can use the system default voice to generate speech or it can specify that the Speech Manager use a particular voice that is available on the current computer system. A voice is a set of characteristics defined in parameters that specify a particular quality of speech. Just as different people’s voices have different tonal qualities, so too can different voices have different qualities. A synthesized voice might sound male or female and might sound like an adult or a child. Some voices sound distinctively synthetic, while others sound more like real people. Figure 4-2 shows how the Speech Manager uses speech channels to synthesize speech with different voices.
  7556. Figure 4-2    The Speech Manager and multiple voices
  7557.  
  7558. As speech-synthesizing technology develops, the voices that your application can access are likely to sound more and more human. Each voice is designed to work with a particular speech synthesizer and can be customized in specific ways to create different effects.
  7559. Voices are usually stored in one of three places. The Speech Manager will first look in the application’s resources file chain when attempting to locate a voice specification record. Then the Speech Manager will look in the System Folder and then the Extensions folder. Voices stored in the System Folder or Extensions folder are normally available to all applications. Voices stored in the resource fork of an application file are private to that application and will not work if the synthesizers they depend on are not installed on a user’s system.
  7560. Most of the time, your application designates the voice that speaks text, and usually that is the default voice. Based on the needs of your users and the way in which you expect them to use voices in your application you can provide access to voices in a number of different ways. You could include access to selecting voices in a dialog box that is available from a menu item such as Voices... Any application that allows users to choose among voices requires additional information about the available voices beyond the information provided by a voice specification record (described in detail on page 4-46), whose data should never be presented to the user. Such additional information might include the name of the voice as well as what script and language it supports. 
  7561. Applications can use the GetVoiceDescription function (described in detail on page 4-66) with a voice specification record to obtain such information in a voice description record (described in detail on page 4-47). You might provide access to voices through a control panel. For information about implementing control panels, see Inside Macintosh: More Macintosh Toolbox. Or, you could implement a voices menu in your application’s main menu bar, if you think that users will want to change the voice often and you have the room available. It’s not a good idea to implement a hierarchical Voices menu since hierarchical menus are harder to use. For more information about choosing a user interface for your application, see Macintosh Human Interface Guidelines.
  7562. Speech Attributes
  7563.  
  7564. Any given person has only one voice, but can alter the characteristics of his or her speech in a number of different ways. For example, a person can speak slowly or quickly and with a low or a high pitch. Similarly, the Speech Manager provides routines that allow you to modify these and other speech attributes, regardless of which voice is in use. A speech attribute is a setting defined for a class of voices or for all voices that affects the quality of speech produced by the Speech Manager. The Speech Manager provides routines to directly alter two speech attributes—speech rate and speech pitch. These routines are described in the section “Changing Speech Attributes” beginning on page 4-73. You can change two other speech attributes—pitch modulation and speech volume—by using the mechanism of speech information selectors, which is described in the section “Speech Information Selectors” beginning on page 4-39.
  7565. The speech rate of a speech channel is the approximate number of words of text that the synthesizer should say in one minute. Slower speech rates make the speech easier to understand, but can be annoyingly tedious to listen to. Some applications, such as aids for the visually impaired, require very fast speech rates. Speech rates are expressed as fixed-point values. Each speech synthesizer determines it own range of speech rates. The speech pitch of a speech channel represents the middle pitch of the voice, roughly corresponding to the key in which a song is played. It is a fixed-point value in the range of 0.000 through 127.000, where 60.000 corresponds to middle C on a conventional piano. Each 1.000-unit change in a value corresponds to a musical half step. This is the same scale used in specifying MIDI note values, as described in the chapter “Sound Manager” in this book. Figure 4-3 shows a piano keyboard with the corresponding MIDI note values.
  7566. Figure 4-3    MIDI note values and corresponding piano keys
  7567.  
  7568. MIDI note values differ from speech pitch values in that they are always integral and have a wider range than speech pitch values. On the scale used to measure both MIDI note values and speech pitches, a change of +12 units corresponds to doubling the frequency (an increase of one octave), while a change of –12 units corresponds to halving the frequency (a decrease of one octave). A frequency is a precise indication of the number of hertz of a sound wave at any instant. If you need to convert between speech pitches and hertz, note that a speech pitch of 60.000 corresponds to 261.625 Hz. Meanwhile, when a speech pitch value rises by one unit, the corresponding hertz value is multiplied by the twelfth root of 2, defined by the Sound Manager constant twelfthRootTwo. The following formula thus converts a speech pitch into hertz:
  7569. hertz = twelfthRootTwo (pitch – 60.000) * 261.625
  7570. In order to calculate speech pitch in terms of hertz, you can use the following formula:
  7571. pitch = 60 + (ln(hertz) – ln(261.625))/ln(twelfthRootTwo)
  7572. Typical voice frequencies might range from around 90 hertz for a low-pitched male voice to about 300 hertz for a high-pitched child’s voice. These frequencies correspond to approximate pitch values in the ranges of 30.000 to 40.000 and 55.000 to 65.000, respectively.
  7573. You can determine the current speech pitch on a speech channel by calling the GetSpeechPitch function, described on page 4-75. You can change the current pitch by calling the SetSpeechPitch function, described on page 4-76. You can also determine the current speech rate and change it by using the GetSpeechRate function, described on page 4-73 and the SetSpeechRate function, described on page 4-74. Changes in speech pitch and speech rate are effective immediately (as soon as the synthesizer can respond), even if they occur in the middle of a word.
  7574. Pitch is the listener’s subjective interpretation of speech’s average frequency. The speech pitch specified is a baseline value corresponding to a particular frequency, from which the actual frequency of generated speech varies with the rises and falls of the intonation of speech. When a person speaks, there is a tune to the speech. Often you are more aware of the singsong quality, or change in the range of speech pitch, of a language that you don’t know rather than one that you speak. The synthesizer must generate this tune in order to sound more human-like. Speech pitch is always described by a set of numbers that specify the range of pitch of the tune a synthesizer generates. This set of numbers can be the middle pitch and how far to deviate from that pitch or it can be the set of pitches within which the semi-tones of the tune can vary. Figure 4-4 shows an example of the range of pitches produced as the phrase “The cat sat on the mat.” is spoken.
  7575. Figure 4-4    An example of pitch range for a voice 
  7576.  
  7577. To simulate the variability in frequency of human speech, the Speech Manager defines the speech attribute of pitch modulation. The pitch modulation of a speech channel is the maximum amount by which the actual frequency of speech generated may deviate from the speech pitch.
  7578. Pitch modulation is also expressed as a fixed-point value in the range of 0.000 to 100.000. A pitch modulation value of 0.000 corresponds to a monotone in which all speech is generated at the frequency corresponding to the speech pitch. Speech generated at this pitch modulation would sound unnaturally robotic. Given a speech pitch value of 46.000, a pitch modulation of 2.000 would mean that the widest possible range of pitches corresponding to the actual frequency of generated text would be 44.000 to 48.000.
  7579. In some synthesizers, the actual pitch modulation may be restricted to a certain range. For example, if a synthesizer supported the full range of pitch modulations, a pitch modulation of 100.000 would result in unintelligible speech. In fact, however, some synthesizers, even with such a setting, produce speech that sounds virtually monotone. Even within a synthesizer, different voices might have different valid pitch modulation ranges. The Speech Manager provides no mechanism for obtaining the range of valid pitch modulations, although some synthesizers may allow applications designed to work with those synthesizers to obtain such ranges.
  7580. You can obtain the pitch modulation by using the GetSpeechInfo function with the soPitchMod speech information selector, and you can change the pitch modulation by using the SetSpeechInfo function with the same selector. Speech information selectors are described in “Speech Information Selectors” beginning on page 4-39.
  7581. The speech volume of a speech channel is the average amplitude at which the channel generates speech. Volumes are expressed in fixed-point units ranging from 0.0 through 1.0. A value of 0.0 corresponds to silence, and a value of 1.0 corresponds to the maximum possible volume. Volume units lie on a scale that is linear with amplitude or voltage. A doubling of perceived loudness corresponds to a doubling of the volume.
  7582. Note that just as a speech synthesizer does not generate speech at a constant frequency, it does not generate speech at a constant amplitude. Even when the speech rate is high, brief pauses break up a steady stream of speech. The speech volume is, like speech pitch, an indicator of an average. There is no way to determine or change the modulation of speech volume.
  7583. A final speech attribute is prosody, the rhythm, modulation, and emphasis patterns of speech.There is no simple mechanism for your application to determine what rhythmic patterns a speech synthesizer is applying to speech. However, you can exert some control over prosody by using prosodic control symbols, discussed in “Prosodic Control Symbols” on page 4-34. Also, you can disable ending prosody, the modulation that distinguishes the end of a sentence or statement in normal speech, by using the SpeakBuffer function, described on page 4-57.
  7584. Speech Channels
  7585.  
  7586. To indicate to the Speech Manager which voice or attributes you would like it to use in generating speech, your application must use a speech channel. A speech channel is a data structure that the Speech Manager uses when processing text; it can be associated with a particular voice and particular speech attributes. Because multiple speech channels can coexist, your application can create several different vocal environments (to simulate a conversation, for example). Because a synthesizer can be associated with only one language and region, your application would need to create a separate speech channel to process each language in bilingual or multilingual text. (Currently, however, only English-producing synthesizers are available.)
  7587. Different speech channels can even generate speech simultaneously, subject to processor capabilities and Sound Manager limitations. This capability should be used with restraint, however, because it can be hard for the user to understand any speech when more than one channel is generating speech at a time. In general, your application should generate speech only at the specific request of the user and should allow the user to turn off speech output. At the very least, your application should include an option that allows the user to view text instead of hearing it. Some users might have trouble understanding speech generated by the Speech Manager, and others might have a hearing deficit. Even users who are able to clearly understand computer-synthesized speech might prefer to read rather than hear.
  7588. Using the Speech Manager, you can identify how many voices are available and sort through an index of the voices to get information about a specified voice such as its gender, age, or the synthesizer with which it is associated. In general, your application does not need to know which speech synthesizer it is using, and in most cases, you do not need to be concerned with which speech synthesizer a voice is associated. Sometimes, however, a speech synthesizer may provide special capabilities beyond that provided by the Speech Manager. For example, a speech synthesizer might allow you to select an option to speak numbers in a nonstandard way. The Speech Manager allows you to determine which synthesizer is associated with a voice for these circumstances and provides hooks that allow your application to take advantage of synthesizer-specific capabilities.
  7589. In general, your application can achieve the best results by not making assumptions about which synthesizers might be available. The user of a 2 MB Macintosh Classic might use a synthesizer with low RAM requirements, while the user of a 20 MB Macintosh Quadra 950 might take advantage of a synthesizer that provides better audio quality at the expense of memory usage. The Speech Manager makes it easy to accommodate both kinds of users. Currently there are three synthesizers available with the Speech Manager. Each synthesizer has its own RAM requirements. To be compatible with all three synthesizers, you must reserve enough space in your application’s heap to accommodate their requirements. In general, reserving around 250 KB per channel that you anticipate using provides enough space for the MacinTalk Pro synthesizer.
  7590. Callback Routines
  7591.  
  7592. The Speech Manager allows you to implement callback routines. With callback routines, you can synchronize speech with other actions. You can use callback routines to obtain information about when a synthesizer has finished speaking a phoneme, reaches a word ending, or finishes speaking. Using this feature, you could highlight text as it is being spoken or synchronize the speech production with a QuickTime movie or animation of a mouth speaking.
  7593. You can also customize speech that your application generates with the Speech Manager by embedding commands in text strings stored in resources in your application or by programmatically embedding commands in commonly spoken text.
  7594. The next section of this chapter shows you how to implement the most commonly used features of the Speech Manager. It demonstrates how you use the SpeakString function to convert a text string into speech without allocating a speech channel, how you can customize speech, how you can obtain more control over speech by allocating speech channels, and how you can make speech easier to understand by embedding commands within text strings. It also shows how to install a custom dictionary to provide more accurate pronunciation of less common words such as names.
  7595.  
  7596.  
  7597. Using the Speech Manager
  7598.  
  7599. You can use the Speech Manager simply to convert Pascal-style strings into speech. This simple technique is described in the chapter “Introduction to Sound on the Macintosh” in this book. This section shows how you can take advantage of more features of the Speech Manager.
  7600. Before you can generate synthetic speech on a Macintosh computer, you need to make sure that the Speech Manager is installed. “Checking for Speech Manager Capabilities” beginning on page 4-12 shows how to check for the availability of the Speech Manager. It also demonstrates how to use the SpeakString function to generate synthesized speech in the most straightforward way.
  7601. To take advantage of most of the Speech Manager’s features, you must allocate a speech channel to pass to Speech Manager functions and dispose of the speech channel when you are finished using it. “Creating, Using, and Disposing of a Speech Channel” beginning on page 4-13 demonstrates how you do this and shows how you can use the SpeakText function to start speech generation from a buffer of text. Some applications permit users to choose a voice from those available to be used for speech generation. The CountVoices, GetIndVoice, and GetVoiceDescription functions support this capability. “Working With Different Voices” beginning on page 4-14 shows how you can use these functions to choose among available voices.
  7602. You can also use the SpeakText function to customize some attributes of speech generation. “Adjusting Speech Attributes” beginning on page 4-16 shows how you can do this. When you start synthesizing speech, you may need a way to stop speech from being generated. You can use the StopSpeech function to stop speech immediately, or you can use the StopSpeechAt function to choose exactly where you want speech stopped. You can stop speech temporarily and then resume it again using the PauseSpeechAt and ContinueSpeech functions. “Pausing Speech” beginning on page 4-18 shows how to pause or stop speech production and begin it again.
  7603. You might need to synchronize speech generation with other activities. For example, your application might include an on screen animation that must be synchronized with speech generation, or your application might need to determine when the Speech Manager has finished processing text on a speech channel so that it can unlock a handle or release some memory. “Implementing Callback Procedures” beginning on page 4-19 shows how you can accomplish these goals.
  7604. If your application uses embedded speech commands to obtain exacting control over speech generation, you should read “Writing Embedded Speech Commands” beginning on page 4-23. This section describes the complete syntax of embedded commands, and provides a guide to all embedded commands supported by the Speech Manager.
  7605. The Speech Manager allows you to enter phonemic text directly. If your application speaks only text that the user writes, this feature is unlikely to be useful to you, because you cannot anticipate what the user might enter. However, if there are a few or many sentences that your application frequently converts into speech, it might be useful to represent parts of these sentences phonemically rather than textually. “Phonemic Representation of Speech” beginning on page 4-32 describes how to convert text to phonemes.
  7606. Some applications might allow the user to use pronunciation dictionaries to override the default pronunciations of certain words. “Including Pronunciation Dictionaries” beginning on page 4-36 explains how you can create a new pronunciation dictionary resource or install an existing pronunciation dictionary resource into a speech channel. The section also explains how you can provide the user with the default phonemic pronunciation of text by using the TextToPhonemes function.
  7607. Checking for Speech Manager Capabilities
  7608.  
  7609. Because the Speech Manager is not available in all system software versions, you should always check for speech capabilities before attempting to use them. Listing 4-1 defines a function that determines whether the Speech Manager is available.
  7610. Listing 4-1    Checking for speech generation capabilities
  7611.  
  7612. FUNCTION MySpeechMgrPresent: OSErr;
  7613. VAR
  7614.     myErr:                OSErr;
  7615.     myFeature:                LongInt;                                                {feature being tested}
  7616. BEGIN
  7617.     {Test Speech Manager present bit.}
  7618.     myerr := Gestalt(gestaltSpeechAttr, myFeature);
  7619.     IF (myErr = noErr) AND (BTst(myFeature, gestaltSpeechMgrPresent)) THEN
  7620.     BEGIN
  7621.         myErr := SpeakString('The Speech Manager is working and');
  7622.         {Wait until synthesizer is done speaking.}
  7623.         WHILE (SpeechBusy <> 0) DO
  7624.         BEGIN                                                            {do nothing}
  7625.         END;
  7626.  
  7627.         myErr := SpeakString('is almost done.');                                                            
  7628.         {Wait until synthesizer is done speaking.}
  7629.         WHILE (SpeechBusy <> 0) DO
  7630.         BEGIN                                                            {do nothing}
  7631.         END;
  7632.         MySpeechMgrPresent := myErr;
  7633.     END;
  7634. END;
  7635. The MySpeechMgrPresent function defined in Listing 4-1 uses the Gestalt function to determine whether the Speech Manager is available. The MySpeechMgrPresent function tests the gestaltSpeechMgrPresent bit, and, if the Speech Manager is present, the MySpeechMgrPresent function speaks the string passed to the SpeakString function. If the Gestalt function cannot obtain the desired information and returns a result code other than noErr, the MySpeechMgrPresent function assumes that the Speech Manager is not available.
  7636. The SpeakString function uses an implied speech channel, that is, the speech channel is automatically created and disposed of by the Speech Manager. The SpeakString function is useful when you need to synthesize Pascal-style strings of fewer than 256 characters. If you need to process text that is longer than 255 characters, then you must allocate a speech channel and use one of the routines that can generate speech in a channel such as the SpeakText or SpeakBuffer function. These routines are much more flexible in that they allow you to speak more text, customize the speech using speech selectors, or alter the generated speech by changing its modulation, pitch, rate, or voice.
  7637. Creating, Using, and Disposing of a Speech Channel
  7638.  
  7639. To take advantage of most of the Speech Manager’s capabilities, you must pass a speech channel to Speech Manager functions. You use the NewSpeechChannel function to create a speech channel. After you are done using a speech channel, you must dispose of it by using the DisposeSpeechChannel function. Listing 4-2 shows how to create a speech channel, start speaking text with the SpeakText function, stop speaking text with the StopSpeech function, and then dispose of the speech channel when the speaking is finished.
  7640. Listing 4-2    Speaking text with a speech channel
  7641.  
  7642. FUNCTION MyUseSpeechChannel: OSErr;
  7643. VAR
  7644.     myErr:            OSErr;
  7645.     myErr2:            OSErr;
  7646.     myStr:            Str255;                                                            {text to be spoken}
  7647. BEGIN
  7648.     myStr := 'Hold the mouse button down to stop speech.';
  7649.     myErr := NewSpeechChannel(NIL, gChannel);                                                                        {create the channel}
  7650.     IF (myErr = noErr) THEN
  7651.     BEGIN                                                                        {speak the string}
  7652.         myErr := SpeakText(gChannel, @myStr[1], Length(myStr));
  7653.         WHILE (SpeechBusy <> 0) DO                                                        {wait until speaking is done}
  7654.         BEGIN            
  7655.             IF (Button) THEN
  7656.             myErr := StopSpeech(gChannel);                                                    {stop speech at mouse down}
  7657.         END;        
  7658.         IF (gChannel <> NIL) THEN
  7659.             myErr2 := DisposeSpeechChannel(gChannel);    {get rid of channel}
  7660.     END;
  7661.     IF (myErr = noErr) THEN 
  7662.         MyUseSpeechChannel := myErr2
  7663.     ELSE
  7664.         MyUseSpeechChannel := myErr;
  7665. END;
  7666. The MyUseSpeechChannel function defined in Listing 4-2 creates a default speech channel using the default system voice. You pass NIL in the first parameter to use the system default voice. You must also pass a global variable to NewSpeechChannel in which is returned a valid speech channel. Once the channel exists, then you can use the SpeakText function to generate speech. To generate synthesized speech, you pass in the channel allocated by NewSpeechChannel in the first parameter, and then you pass a pointer to the text that you want to speak as well as the length of the text that you want the Speech Manager to attempt to speak. That is, you can pass a pointer to a buffer of text that is 500 bytes long, but specify that only the first 10 bytes get spoken. Then MyUseSpeechChannel uses the SpeechBusy function in a WHILE loop to allow the text to be completely spoken before disposing of the channel.
  7667. When the designated action to stop the speaking occurs, which in this example is the user pressing the mouse button, MyUseSpeechChannel halts speech production. In this case, the StopSpeech function stops the speech immediately (as soon as the synthesizer can). You need to pass StopSpeech the variable that identifies the channel on which the speech is currently being synthesized. If you want to have more control over when the speech is stopped, you can use the StopSpeechAt function, which allows you to stop speech immediately, at the end of a word, or at the end of a sentence. See the description of the StopSpeechAt function on page 4-60 for more information.
  7668. Once you are done using the speech channel that was created with NewSpeechChannel, you must dispose of it. The MyUseSpeechChannel function calls DisposeSpeechChannel with the global variable that identifies the channel currently in use.
  7669. Working With Different Voices
  7670.  
  7671. When you work with speech channels, you can set a voice for a particular channel. When you set a voice, you may want to filter out certain of its characteristics in order to identify the one you want. For example, in an educational software application for elementary school students, you may want to use only children’s voices. In order to choose the voice you want, you get a voice description record that contains information about a voice such as the size of the voice, the name of the voice, the age and gender of the voice, and the synthesizer with which it works. You can get the number of available voices using the CountVoices function. You can cycle through the available voices and identify the one you want to use by using the GetIndVoice function. Then you fill out a voice description record using the GetVoiceDescription function. Listing 4-3 shows how to get identifying information about a voice.
  7672. Listing 4-3    Getting a description of a voice
  7673.  
  7674. FUNCTION MyInstallBoysVoice: OSErr;
  7675. VAR
  7676.     myErr:                    OSErr;
  7677.     myIndex:                    Integer;
  7678.     myNumVoices:                    Integer;
  7679.     myVoice:                    VoiceSpec;
  7680.     myFound:                    VoiceSpec;
  7681.     myInfo:                    VoiceDescription;
  7682. BEGIN
  7683.     myFound := NIL;
  7684.     myErr := CountVoices(myNumVoices);                                                            {count voices}
  7685.     IF myErr = noErr THEN
  7686.     BEGIN
  7687.         FOR myIndex := 0 to myNumVoices DO                                                        {loop through all voices}
  7688.         BEGIN
  7689.             myErr := GetIndVoice(myIndex, @myVoice);
  7690.             IF myErr = noErr THEN
  7691.             BEGIN
  7692.                 myErr := GetVoiceDescription(@myVoice, @myInfo, sizeof(myInfo));
  7693.                 IF myErr = noErr THEN                                                {check if a boy's voice}
  7694.                     IF (myVoice.age < 16) AND (myVoice.gender = kMale) THEN
  7695.                         myFound := myVoice;
  7696.             END;
  7697.         END; {FOR}
  7698.         IF myFound <> NIL THEN                                                        {install boy's voice}
  7699.             myErr := NewSpeechChannel(@myFound, gChannel);
  7700.     END;
  7701.     MyInstallBoysVoice := myErr;                                                            {return result code}
  7702. END;
  7703. The MyGetVoiceInfo function checks to see how many voices are available. Once you have identified the list of available voices, you can index through the voices to select one about which you want to get information. You pass the number of the voice index in the first parameter of the GetIndVoice function. (This number cannot be larger than the number of voices.) GetIndVoice returns a voice specification record in the location specified in the second parameter— in this case, in the location of the pointer @myVoice. This sample cycles through the available voices looking for a male child’s voice.
  7704. The voice specification record contains two identifiers: the creator identification of the required synthesizer and the voice identification of the voice.In order to get specific information about the voice you want to use, you need to call the GetVoiceDescription function. You need to pass a pointer to the voice specification record in the first parameter of the GetVoiceDescription function. GetVoiceDescription returns the voice description record in the location pointed to in the second parameter, @info. The voice description record contains information about the voice such as its age or gender.
  7705. To specify which voice you want to use, you pass a pointer to the voice specification record as the first parameter to NewSpeechChannel. In this case, when the male child’s voice is identified, it’s voice specification record is passed to NewSpeechChannel, which allocates a channel with the specified voice. Note that this sample code contains limited error checking.
  7706. Adjusting Speech Attributes
  7707.  
  7708. Speech attributes are settings defined for a class of voices or for all voices that affect the quality of speech produced by the Speech Manager. In general, an application should not try to second-guess the developers of a voice or synthesizer by arbitrarily setting a speech attribute. However, there are some cases in which you would want to adjust the rate of speech (how many words per minute are spoken) or the speech pitch (the listener’s subjective interpretation of speech’s average frequency). Listing 4-4 shows how to adjust the speech pitch and speech rate of a particular channel.
  7709. Listing 4-4    Changing the speech rate and pitch
  7710.  
  7711. FUNCTION MyAdjustSpeechAttributes: OSErr;
  7712. VAR
  7713.     myErr:                OSErr;
  7714.     myErr2:                OSErr;
  7715.     myPitch:                Fixed;
  7716.     myRate:                Fixed;
  7717.     myStr:                Str255;
  7718. BEGIN
  7719.     myStr := 'This is the old pitch and rate.';
  7720.     myErr := NewSpeechChannel(NIL, gChannel);                                                             {allocate a channel}
  7721.     IF myErr = noErr THEN
  7722.    BEGIN                                                                   {speak a string}
  7723.         myErr := SpeakText(gChannel, @myStr[1], Length(myStr));
  7724.         WHILE (SpeechBusy <> 0) DO                                                           {wait for speech to finish}
  7725.         BEGIN
  7726.         END;
  7727.         {Find the current speech pitch.}
  7728.         myErr := GetSpeechPitch(gChannel, @myPitch);
  7729.         myPitch := myPitch * 2;                                                                      {double the pitch}
  7730.         IF myErr = noErr THEN
  7731.             myErr := SetSpeechPitch(gChannel, myPitch);                                                             {change the pitch}
  7732.  
  7733.         {Find the current speech rate.}
  7734.         IF myErr = noErr THEN
  7735.             myErr := GetSpeechRate(gChannel, @myRate);
  7736.         myRate := myRate * 2;                                                                        {double the rate}
  7737.         IF myErr = noErr THEN
  7738.             myErr := SetSpeechRate(gChannel, myRate);                                                                {change the rate}
  7739.         {Speak a string with new attributes.}
  7740.         myStr := 'This is the new pitch and rate.';
  7741.         myErr := SpeakText(gChannel, @myStr[1], Length(myStr));
  7742.         WHILE (SpeechBusy <> 0) DO                                                {wait for speech to finish}
  7743.         BEGIN
  7744.         END;
  7745.         {Dispose of the speech channel.}
  7746.         IF gChannel <> NIL THEN
  7747.             myErr2 := DisposeSpeechChannel(gChannel);
  7748.     END;
  7749.     IF myErr = noErr THEN
  7750.         MyAdjustSpeechAttributes := myErr2
  7751.     ELSE
  7752.         MyAdjustSpeechAttributes := myErr;
  7753. END;
  7754. The MyAdjustSpeechAttributes function first allocates a speech channel, as demonstrated previously. Then the MyAdjustSpeechAttributes function speaks a string to demonstrate the default speech rate and pitch for the default system voice. After the speech synthesis is finished, MyAdjustSpeechAttributes calls the GetSpeechPitch function with a valid speech channel and a pointer to a fixed-point value in which the value of the current speech pitch is returned. Then MyAdjustSpeechAttributes doubles the value of the speech pitch by multiplying and passes the new value to the SetSpeechPitch function.
  7755. MyAdjustSpeechAttributes repeats this sequence to determine the speech rate using the GetSpeechRate function, doubles the rate, and sets a new speech rate by passing the new rate value to the SetSpeechRate function. Next, MyAdjustSpeechAttributes calls SpeakText again to demonstrate the new speech pitch and rate. Creating a loop with the SpeechBusy function allows the synthesizer to finish speaking its text, and then MyAdjustSpeechAttributes disposes of the active channel.
  7756. When you set a rate value, each synthesizer may or may not be able to support that exact value. A synthesizer will attempt to set the value you specify, but it may substitute a value that it can support that is the closest it can come to your value. Don’t be alarmed if GetSpeechRate returns a value other than the one you thought you set. The value returned is the closest value to the one set that the synthesizer is capable of reproducing.
  7757. Pausing Speech
  7758.  
  7759. When you start synthesizing speech, you may need a way to stop speech that is being generated. For example, your application might support a Stop Speech menu command to let users stop speech when they want to. Also, you should usually stop speech when you receive a suspend event. You can use StopSpeech to stop speech immediately, or you can use StopSpeechAt to choose exactly where you want speech stopped. You can also stop speech temporarily and then resume it again using the PauseSpeechAt and ContinueSpeech functions. Listing 4-5 shows how you might do this.
  7760. Listing 4-5    Pausing and continuing speech production
  7761.  
  7762. FUNCTION MyPauseAndContinueSpeech: OSErr;
  7763. VAR
  7764.     myErr, myErr2:                        OSErr;
  7765.     myStr:                        Str255;
  7766. BEGIN
  7767.     gChannel := NIL;
  7768.     myStr := 'Hold the mouse button down to test pause speech at immediate.';
  7769.     myErr := NewSpeechChannel(NIL, gChannel);                                                            {open speech channel}
  7770.     IF myErr = noErr THEN
  7771.     BEGIN                                                            {speak some text}
  7772.         myErr := SpeakText(gChannel, @myStr[1], Length(myStr));
  7773.         WHILE (SpeechBusy <> 0) DO                                                        {wait for speech to finish}
  7774.             IF (Button) THEN
  7775.             BEGIN                                                    {stop speech immediately}
  7776.                 myErr := PauseSpeechAt(gChannel, kImmediate);
  7777.                 IF myErr = noErr THEN
  7778.                     WHILE (Button) DO                            {while mouse button is down, do nothing}
  7779.                     BEGIN
  7780.                     END;                            {on mouse up, resume speaking}
  7781.                     myErr := ContinueSpeech(gChannel);
  7782.         END;
  7783.         IF gChannel <> NIL THEN                                        {dispose of channel}
  7784.             myErr2 := DisposeSpeechChannel(gChannel);
  7785.     END;
  7786.     IF myErr = noErr THEN
  7787.         MyPauseAndContinueSpeech := myErr2
  7788.     ELSE
  7789.         MyPauseAndContinueSpeech := myErr;
  7790. END;
  7791. The MyPauseAndContinueSpeech function defined in Listing 4-5 begins by allocating a speech channel using the default system voice. It then begins to speak some text. MyPauseAndContinueSpeech uses a busy loop to allow the speech to be completely spoken before finishing the subroutine. Then, when the designated action occurs, in this case the mouse button being depressed by a user, MyPauseAndContinueSpeech calls PauseSpeechAt with the currently active channel and a constant that defines where to stop the speech. This example uses the constant kImmediate to indicate that the speech should cease wherever it us currently being processed by the synthesizer. There are also constants that define the end of a word and the end of a sentence as appropriate stopping places.
  7792. When the mouse button is released, MyPauseAndContinueSpeech calls the ContinueSpeech function with the variable identifying the paused speech channel. When paused immediately, the synthesizer resumes speaking at the beginning of the word that was interrupted. While the speech is being generated, MyPauseAndContinueSpeech continues to call SpeechBusy to determine if the channel is still being used to process speech. When the channel is no longer busy, MyPauseAndContinueSpeech calls DisposeSpeechChannel to release the memory used by the speech channel.
  7793. Implementing Callback Procedures
  7794.  
  7795. The Speech Manager makes it easy for you to synchronize other activities to speech generation by allowing you to install various types of callback procedures on a speech channel. A callback procedure is a procedure that executes whenever a certain type of event is about to occur or has occurred. For example, you might use a word callback procedure to ensure that whenever the Speech Manager is about to speak a word, the word is visible onscreen. Callback procedures also allow you to synchronize more mundane activities with the Speech Manager; for example, you might need to know when you can dispose of a certain text buffer that you had asked the Speech Manager to speak. This section provides an overview of the different callback procedures that you can define.
  7796. The soTextDoneCallBack and soSpeechDoneCallBack speech information selectors allow you to designate text-done and speech-done callback procedures. A text-done callback procedure executes whenever the Speech Manager finishes processing a buffer of text to be spoken. This procedure usually executes before the Speech Manager has finished generating speech from the text and indeed often before it has started. The text-done callback procedure provides a mechanism that allows you to specify to the Speech Manager an additional buffer of text to be spoken, so that speech is generated continuously. Once your text-done callback procedure executes, you can release the memory occupied by the text buffer processed. A speech-done callback procedure does not execute until after the Speech Manager has completed generating speech from a buffer of text.
  7797. If your application uses or supports embedded speech commands, it may need to use the soSyncCallBack and soErrorCallBack speech information selectors to designate a synchronization callback procedure or an error callback procedure. A synchronization callback procedure executes whenever the Speech Manager encounters a synchronization command embedded within a text buffer to be spoken. An error callback procedure executes whenever the Speech Manager encounters an error when attempting to process an embedded speech command. The Speech Manager passes information about the synchronization message or type of error to your callback procedure. If your application does not use synchronization or error callback procedures, it can obtain information about synchronization or error messages by continually polling the speech channel by using the GetSpeechInfo function with the soErrors or soRecentSync selectors.
  7798. The soPhonemeCallBack and soWordCallBack speech information selectors allow you to designate a phoneme callback procedure and a word callback procedure, respectively. A phoneme callback procedure executes whenever a phoneme is about to be spoken on a speech channel. A word callback procedure executes whenever a word is about to be spoken on a speech channel.
  7799. Since callback procedures execute at interrupt time they face several restrictions, as discussed in detail in Inside Macintosh: Processes. Most significantly, your callback procedure must not allocate or move memory or call any Toolbox or Operating System routine that might do so. Thus, typically a callback procedure simply sets a flag variable; for example, a phoneme callback procedure might change a variable that indicates which phoneme is being spoken. Your application can then poll this flag variable each time through its main event loop and perform whatever activity is desired if it finds that the flag variable has changed. Remember to design callback procedures to execute quickly. 
  7800. Because they execute at interrupt time, callback procedures also cannot access application global variables unless the A5 register contains the value of the application’s A5, as discussed in Inside Macintosh: Memory. Fortunately, the Speech Manager provides a mechanism that makes it easy to ensure that A5 is set correctly. Your application can call the SetSpeechInfo function with the soCurrentA5 selector to pass the application’s A5 in the speechInfo parameter to the Speech Manager. The Speech Manager will then set the A5 register to the passed value whenever it executes an application-defined callback procedure for that speech channel.
  7801. Sometimes your application might wish to provide a callback procedure with additional information beyond that which can be provided by examining application global variables. For example, a callback procedure might need to know from which document speech is being generated. Your application can use the SetSpeechInfo function with the soRefCon selector to specify a 4-byte reference constant value—for example, a handle to a document record—that the Speech Manager passes to all callback procedures on a particular speech channel. Your application can use the same callback procedure on multiple speech channels, for each of which the Speech Manager can pass a different value to the callback procedure. Thus, as long as your application never uses a single speech channel to generate speech on multiple documents simultaneously, it can use the reference constant value mechanism to pass document-specific information to a callback procedure. Typically, you use the reference constant to contain a pointer or handle to more extensive information that the callback procedure would require.
  7802. Listing 4-6 shows how you can indicate to the Speech Manager both the value to which it should set the A5 register when it executes a callback procedure on a particular speech channel and the reference constant value to pass to that callback procedure.
  7803. Listing 4-6    Setting up a speech channel for callbacks
  7804.  
  7805. FUNCTION MySetupCallbacks (chan: SpeechChannel; refCon: LongInt): OSErr;
  7806. VAR
  7807.     myA5:                 LongInt;                                {application's A5}
  7808.     myErr:                 OSErr;
  7809. BEGIN
  7810.     myA5 := SetCurrentA5;                                                {get application's A5}
  7811.  
  7812.     {Pass A5 value to speech channel.}
  7813.     myErr := SetSpeechInfo(chan, soCurrentA5, Ptr(myA5));
  7814.     IF myErr = noErr THEN                                                {set the reference constant}
  7815.         myErr := SetSpeechInfo(chan, soRefCon, Ptr(refCon));
  7816.  
  7817.     MySetupCallbacks := myErr;
  7818. END;
  7819. The MySetupCallbacks function defined in Listing 4-6 uses the SetSpeechInfo function with both the soCurrentA5 and the soRefCon selectors to prepare a specific speech channel for callbacks. Note that your application can call MySetupCallbacks as many times as desired for any particular speech channel; you might do this if you want to change the reference constant value to be passed to the speech channel.
  7820. Unlike other selectors, the soCurrentA5 and soRefCon selectors do not require that you pass a pointer to the information you are specifying in the speechInfo parameter. Because an application’s A5 value and a speech channel’s reference constant value are always each 4 bytes long (the same size as the speechInfo parameter), your application passes these values directly, casting them to pointer values.
  7821. After your application sets up the A5 register and defines a reference constant value, it can install the appropriate type or types of callback procedure. Listing 4-7 shows how you might install a word callback procedure.
  7822. Listing 4-7    Installing a word callback procedure
  7823.  
  7824. PROCEDURE MyInstallWordCallback (chan: SpeechChannel; callbackProc: ProcPtr;
  7825.                                                 refCon: LongInt);
  7826. VAR
  7827.     myErr:                OSErr;
  7828. BEGIN
  7829.     myErr := MySetupCallbacks(chan,  refCon);                                                            {set up callbacks}
  7830.     myErr := SetSpeechInfo(chan, soWordCallBack, callbackProc);
  7831.     IF myErr <> noErr THEN
  7832.         DoError(myErr);                                                        {respond to an error}
  7833. END;
  7834. The MyInstallWordCallback procedure defined in Listing 4-7 first prepares for callbacks by calling the MySetupCallbacks function defined in Listing 4-6 for the speech channel and reference constant value specified by the chan and refCon parameters, respectively. Then it installs the callback procedure specified by the callbackProc parameter by using the SetSpeechInfo function with the soWordCallBack speech information selector. If, for example, you want to pass to your word callback procedure a pointer to the window containing the document being used for speech generation, you might call the MyInstallWordCallback procedure like this:
  7835. MyInstallWordCallback(mySpeechChan, @MyWordCallBack, LongInt(myWindow));
  7836. Listing 4-8 defines a simple word callback procedure.
  7837. Listing 4-8    A typical word callback procedure
  7838.  
  7839. PROCEDURE MyWordCallback (chan: SpeechChannel; refCon: LongInt;
  7840.                                     wordPos: LongInt; wordLen: Integer);
  7841. BEGIN
  7842.     gWindowBeingRead := WindowPtr(refCon);
  7843.     gWordPos := wordPos;
  7844.     gWordLen := wordLen;
  7845. END;
  7846. sWARNING
  7847. Callback procedures are called at interrupt time and therefore must not attempt to allocate, move, or dispose of memory; dereference an unlocked handle; or call other routines that do so. Also, a callback procedure is a Pascal procedure and must preserve all registers other than A0–A1 and D0–D2. s
  7848. Because of the restrictions on callback procedures, a typical callback procedure usually just sets global flag variables based on the information passed to it. In Listing 4-8, the callback procedure copies information from the refCon, wordPos, and wordLen parameters to the three global variables gWindowBeingRead, gWordPos, and gWordLen. You can then call a routine to check the values of these global variables once each time through your application’s event loop and respond appropriately if the gWindowBeingRead global variable is not NIL. (Your application would have to initialize the variable to NIL.) For example, the routine might ensure that the word about to be spoken is visible onscreen and scroll the document appropriately if it is not.
  7849. Although they have different uses, speech-done callback procedures, synchronization callback procedures, error callback procedures, and phoneme callback procedures are typically defined in ways similar to that of the word callback procedure in Listing 4-8. See “Application-Defined Routines” beginning on page 4-82 for complete information on callback routines.
  7850. Text-done callback procedures are usually more complex than the other types. You can use a text-done callback procedure simply to determine when the Speech Manager has completed processing a buffer of input text. The callback procedure can just set a global flag variable that is inspected once each time through the application’s main event loop; when the flag variable indicates that the input buffer processing is complete, you can dispose of the input buffer.
  7851. Writing Embedded Speech Commands
  7852.  
  7853. Embedded speech commands allow you to customize the quality of speech output by fine tuning it. You can make speech much easier to understand than the default way in which text is spoken by a synthesizer. An embedded speech command is a command embedded within a text buffer to be spoken by the Speech Manager that causes the Speech Manager to take a certain action. For example, you could use an embedded speech command to emphasize a particular word in a text string to make it stand out to the user.
  7854. An advantage of this technique is that your application needs to call only the standard functions that generate speech: SpeakString, SpeakText, or SpeakBuffer. To change the way a phrase is generated, you do not need to change any of your application’s code; you merely need to change the embedded command text. Your application can also use embedded speech commands even if it speaks text created by the user, as opposed to a limited set of phrases. Before passing text to the Speech Manager, your application could embed various commands within the text. For example, a word-processing application might embed commands that tell the Speech Manager to put extra emphasis around words that the user has boldfaced or underlined.
  7855. Embedded Command Delimiters
  7856.  
  7857. When processing input text data, speech synthesizers look for special sequences of characters called command delimiters. These character sequences are usually defined to be unusual pairings of printable characters that would not normally appear in the text. When a begin command delimiter string is encountered in the text, the following characters are assumed to contain one or more commands. The synthesizer will attempt to parse and process these commands until an end command delimiter string is encountered. By default, the begin command delimiter string is “[[”, and the end command delimiter string is “]]”. You can change the command delimiters if necessary, but you should be sure to use printable characters that are not in common use. Be sure to change the default delimiters back to the assigned characters when you are done with the speech processing for which you changed the delimiters. For example, if your application needs to speak text that naturally contains the default delimiter characters, then it should temporarily change the delimiters to sequences not included in the text. Or, if your application does not wish to support embedded speech commands, then it can disable such processing by setting both the begin command delimiter and the end command delimiter to 2 NIL bytes.
  7858. Syntax of Embedded Speech Commands
  7859.  
  7860. This section describes the syntax of embedded speech commands in detail. All embedded speech commands must be enclosed by the begin command delimiter and the end command delimiter, as follows:
  7861. [[emph +]]
  7862. All speech commands require parameters immediately following the speech command. The parameter to the speech emphasis command above is the plus sign. The format of the parameter depends on the command issued. Numeric type parameters include fixed-point numbers, bytes, integers, and 32-bit values. Hexadecimal numbers may be entered using either Pascal or C syntax; $1A22 and 0x1A22 are both acceptable.
  7863. A common type of parameter is an operating-system type parameter, used generally to specify a particular selector. For example,
  7864. [[inpt PHON]]
  7865. changes the text-processing mode so that the Speech Manager interprets text to be composed of phonemes.
  7866. Some commands allow you to specify an absolute value by including just a number as the parameter or to specify a relative value by adding a + or – character. For example, the following command raises the speech volume by 0.1: 
  7867. [[volm +0.1]]
  7868. Your application can place multiple commands within a single set of delimiters by using semicolons–for example:
  7869. [[volm 0.3 ; rate 165]]
  7870. It is suggested that you precede all other embedded speech commands by a format version command. This command indicates to speech synthesizers the format version to be used by all subsequent embedded speech commands. The current format version is 1. You could write a format version command for the current format version like this:
  7871. [[vers $00000001]]
  7872. Table 4-1 provides a formalization of the embedded command syntax structure, subject to these conventions:
  7873. n    Items enclosed in angle brackets (< and >) represent logical units that either are defined further below in the table or are atomic units that should be self-explanatory, in which case the explanations are provided in italic type. All logical units are listed in the first column.
  7874. n    Items enclosed in single brackets ([ and ]) are optional.
  7875. n    Items followed by an ellipsis (…) may be repeated one or more times.
  7876. n    For items separated by a vertical bar (|), any one of the listed items may be used.
  7877. n    Multiple space characters between tokens may be used if desired.
  7878. n    Multiple commands within a single set of parameters should be separated by semicolons.
  7879. Table 4-1    The embedded command syntax structure
  7880. Identifier    Syntax    
  7881. CommandBlock    <BeginDelimiter> <CommandList> <EndDelimiter>    
  7882. BeginDelimiter    <String1> | <String2>    
  7883. EndDelimiter    <String1> | <String2>    
  7884. CommandList     <Command> [; <Command>]…    
  7885. Command     <CommandSelector> [parameter]…    
  7886. CommandSelector    <OSType>    
  7887. Parameter    <OSType> | <String1> | <String2> | <StringN> | <FixedPointValue> | <32BitValue> | <16BitValue> | <8BitValue>    
  7888. String1    <Character>     
  7889. String2    <Character> <Character>     
  7890. StringN    [<Character>…]     
  7891. OSType    <Character> <Character> <Character> <Character>    
  7892. 32BitValue    <OSType> | <LongInt> | <HexLongInt>     
  7893. 16BitValue    <Integer> |<HexInteger>    
  7894. 8BitValue    <Byte> | <HexByte>    
  7895. FixedPointValue    <Decimal number: 0.0000 £ N £ 65,535.9999>    
  7896. LongInt    <Decimal number: 0 £ N £ 4,294,967,295>    
  7897. HexLongInt    <Hex number: 0x00000000 £ N £ 0xFFFFFFFF>    
  7898. Integer    <Decimal number: 0 £ N £ 65,535>    
  7899. HexInteger    <Hex number: 0x0000 £ N £ 0xFFFF>    
  7900. Character    <Any printable character (for example, A, b, *, #, x)>    
  7901. Byte    <Decimal number: 0 £ N £ 255>    
  7902. HexByte    <Hex number: 0x00 £ N £ 0xFF>    
  7903.  
  7904. Table 4-2 outlines the set of currently defined embedded speech commands in alphabetical order and uses the same syntax conventions as Table 4-1. Note that when writing embedded speech commands, you omit the symbols like angle brackets and ellipses that are used here for explanatory purposes. 
  7905. Table 4-2    Embedded speech commands(continued)
  7906. Command and selector    Command syntax and description    
  7907. Character mode (char)    char NORM | LTRLThe character mode command sets the word-speaking mode of the speech channel. When NORM mode is selected, the synthesizer attempts to automatically convert words into speech. This is the most basic function of the text-to-speech synthesizer. When LTRL mode is selected, the synthesizer speaks every word, number, and symbol character by character. Embedded command processing continues to function normally, however.This embedded speech command is analogous to the soCharacterMode speech information selector.    
  7908. Comment (cmnt)    cmnt [<Character>…]The comment command is ignored by speech synthesizers. It enables a developer to insert a comment that will not be spoken into a text stream for documentation purposes. Note that all characters following the cmnt selector up to <EndDelimiter> are part of the comment.     
  7909. Delimiter (dlim)    dlim <BeginDelimiter> <EndDelimiter>The delimiter command changes the character sequences that mark the beginning and end of all subsequent commands to the character sequences specified. The new delimiters take effect after the command list containing this command has been completely processed. If the delimiter strings are empty, an error is generated.This embedded speech command is analogous to the soCommandDelimiter speech information selector.    
  7910. Emphasis (emph)    emph + | -The emphasis command causes the next word to be spoken with either greater emphasis or less emphasis than would normally be used. Using + will force added emphasis, while using – will force reduced emphasis. For an illustration of using the emphasis command, see the section “Examples of Embedded Speech Commands” beginning on page 4-30.     
  7911. Input mode (inpt)    inpt | TEXT | PHONThe input mode command switches the input-processing mode to either normal text mode or phoneme mode. Passing TEXT sets the mode to text mode; passing PHON sets the mode to phoneme mode. Some speech synthesizers might define additional speech input mode selectors. In phoneme mode, characters are interpreted as representing phonemes, as described in “Phonemic Representation of Speech” on page 4-32.This embedded speech command is analogous to the soInputMode speech information selector.    
  7912. Number mode (nmbr)    nmbr NORM | LTRLThe number mode command sets the number-speaking mode of the speech synthesizer. When NORM mode is selected, the synthesizer attempts to automatically speak numeric strings as intelligently as possible. When LTRL mode is selected, numeric strings are spoken digit by digit. When the word-speaking mode is set to literal via the character mode command or the soCharacterMode speech information selector, numbers are spoken digit by digit regardless of the current number-speaking mode.This embedded speech command is analogous to the soNumberMode speech information selector.    
  7913. Baseline pitch (pbas)    pbas [+ | -] <FixedPointValue>The baseline pitch command changes the current speech pitch for the speech channel to the fixed point value specified. If the pitch number is preceded by a + or – character, the speech pitch is adjusted relative to its current value. Base pitch values are always positive numbers in the range from 1.000 to 127.000.This embedded speech command is analogous to the soPitchBase speech information selector. For a discussion of speech pitch, see the section “Speech Attributes” beginning on page 4-6.     
  7914.  
  7915. continued        
  7916. Pitch modulation (pmod)    pmod [+ | -] <FixedPointValue>The pitch modulation command changes the modulation range for the speech channel based on the modulation depth fixed-point value specified. The actual pitch of generated speech might vary from the baseline pitch up or down as much as the modulation depth. If the modulation depth number is preceded by a + or – character, the pitch modulation is adjusted relative to its current value. Speech pitches fall in the range of 0.000 to 127.000. This embedded speech command is analogous to the soPitchMod speech information selector. For a discussion of speech pitch, see the section “Speech Attributes” beginning on page 4-6.     
  7917. Speech rate (rate)    rate [+ | -] <FixedPointValue>The speech rate command sets the speech rate in words per minute on the speech channel to the fixed-point value specified. If the rate value is preceded by a + or – character, the speech rate is adjusted relative to its current value. Speech rates fall in the range 0.000 to 65535.999, which translate into 50 to 500 words per minute. Normal human speech rates are around 180 to 220 words per minute. This embedded speech command is analogous to the soRate speech information selector. For a discussion of speech rate, see the section “Speech Attributes” beginning on page 4-6.     
  7918. Reset (rset)    rset <32BitValue>The reset command will reset the speech channel’s voice and speech attributes back to default values. The parameter has no effect; it should be set to 0.This embedded speech command is analogous to the soReset speech information selector.    
  7919. Silence (slnc)    slnc <32BitValue>The silence command causes the synthesizer to generate silence for the number of milliseconds specified. The timing of the silence will vary widely between synthesizers. For an illustration of using the silence command, see the section “Examples of Embedded Speech Commands” beginning on page 4-30.     
  7920. Synchronization (sync)    sync <32BitValue>The synchronization command causes the application’s synchronization callback procedure to be executed. The callback is made as the audio corresponding to the next word begins to sound. The callback procedure is passed the 32-bit value specified in the command. Synchronization callback procedures are described in “Synchronization Callback Procedure” beginning on page 4-85.    
  7921. Format version (vers)    vers <32BitValue>The format version command informs the speech synthesizer of the format version that subsequent embedded speech commands will use. This command is optional but is recommended to ensure that embedded speech commands are compatible with all versions of the Speech Manager. The current format version is $0001.    
  7922. Speech volume (volm)    volm [+ | -] <FixedPointValue>The speech volume command changes the speech volume on the speech channel to the fixed-point value specified. If the volume value is preceded by a + or – character, the speech volume is adjusted relative to its current value. Volumes are expressed in fixed-point units ranging from 0.000 through 1.000. A value of 0.0 corresponds to silence, and a value of 1.0 corresponds to the maximum possible volume. Volume units lie on a scale that is linear with amplitude or voltage. A doubling of perceived loudness corresponds to a doubling of the volume. This embedded speech command is analogous to the soVolume speech information selector.    
  7923. Synthesizer-specific (xtnd)    xtnd <OSType> [<Parameter>…]The synthesizer-specific command enables synthesizer-specific commands to be embedded in the input text stream. Synthesizer-specific speech commands are processed by the speech synthesizer whose creator ID is specified in the first parameter and by other speech synthesizers that support commands aimed at the synthesizer with the specified creator ID. The format of the data following the parameter is entirely dependent on the synthesizer being used. This embedded speech command is analogous to the soSynthExtension speech information selector, described in “Speech Information Selectors” beginning on page 4-39.    
  7924.  
  7925. While embedded speech commands are being processed, several types of errors might be detected and reported to your application. If you have enabled error callbacks by using the SetSpeechInfo function with the soErrorCallBack selector, the error callback procedure will be executed once for every error that is detected, as described in “Error Callback Procedure” beginning on page 4-86. If you have not enabled error callbacks, you can still obtain information about the errors encountered by calling the GetSpeechInfo function with the soErrors selector. The following errors might be detected during processing of embedded speech commands:badParmVal    –245    Parameter value is invalid    
  7926. badCmdText    –246    Embedded command syntax or parameter problem    
  7927. unimplCmd    –247    Embedded command is not implemented on synthesizer    
  7928. unimplMsg    –248    Unimplemented message    
  7929. badVoiceID    –250    Specified voice has not been preloaded    
  7930. badParmCount    –252    Incorrect number of embedded command arguments    
  7931.  
  7932. Examples of Embedded Speech Commands
  7933.  
  7934. If you use just a few of the embedded speech commands, you can markedly increase the understandability of text spoken by your application. Your application knows more about the speech being produced than a speech synthesizer does. A synthesizer speaks text according to a predetermined set of rules about language production. Therefore, the voices available on a Macintosh computer with the Speech Manager installed sound very synthetic and sometimes robotic because the pronunciation rules are formalized. You can make the speech produced by the synthesizer sound a lot more human by observing some simple rules of human speech and embedding speech commands in text according to these conventions. The techniques presented in this section could be applied when your application is having a dialog with the user or speaking some error messages or announcements.
  7935. The most common technique humans use in speaking is to emphasizing or deemphasizing words in a sentence. This change in emphasis marks for the listener new and important information by highlighting it vocally, making it easier for the listener to recognize important or different words in a sentence. For example, in a calendar-scheduling program, your application might speak a list of appointments for a day. The following text strings would all be spoken with the same tune and rhythm.
  7936. At 4pm you have a meeting with Kim Silver.
  7937. At 6pm you have a meeting with Tim Johnson.
  7938. At 7pm you have a meeting with Mark Smith.
  7939. The example that follows shows how you use embedded speech commands to deemphasize repeated words in similar sentences and highlight new information in a sentence. The first sentence of the following example sounds fairly acceptable. The second sentence deemphasizes the repeated words have and meeting to point out the new information—with whom the meeting is. The choice of which words to emphasize or deemphasize is based on what was spoken in the preceding sentence.To use the embedded command emph (emphasis), you insert it followed by a plus or minus sign before the word you want emphasized or deemphasized. The emph command lasts for a duration of one word.
  7940. At 4:15 you have a meeting with Ray Chiang.
  7941. At 6:30, you [[emph -]] have a [[emph -]] meeting with 
  7942. William Ortiz.
  7943. At 7pm, you [[emph -]] have a [[emph -]] meeting with 
  7944. Eric Braz Ford.
  7945. As shown in the next example, you can further enhance this text by spelling out the numbers so that you can emphasize changes in increments of time. For example, the following sentences deemphasize the repeated word six to highlight the difference between the meetings; which both occur between six and seven o’clock.
  7946. At four fifteen you have a meeting with Lori Kaplan.
  7947. At six [[emph -]] fifteen, you [[emph -]] have a [[emph -]] meeting with Tim Monroe.
  7948. At [[emph -]] six thirty, you [[emph -]] have a [[emph -]] meeting with Michael Abrams.
  7949. Another use of the emphasis embedded command is to make confusing, boring, or mechanical sounding text more understandable. One example of this is strings of nouns that refer to one entity (called complex nominals) that when spoken differently have a different meeting.
  7950. 1a. Steel warehouse.
  7951. 1b. Steel [[emph -]] warehouse.
  7952. 2a. French teachers.
  7953. 2b. French [[emph -]] teachers.
  7954. In the first example, phrase 1a, steel warehouse, refers to a warehouse made of steel, in which anything could be stored. But phrase 1b describes a warehouse of unspecified construction in which steel is stored. In the second example, phrase 2a, French teachers, refers to teachers from France who teach any subject. In the same example, phrase 2b specifies people from anywhere who teach French classes. You can use this technique of deemphasizing words in phrases to help users correctly understand the meaning of text spoken from your application.
  7955. You use the emph command to emphasize words in order to contrast them. You contrast words that are similar to words found later in a sentence to help distinguish new information.
  7956. You have [[emph +]] 3 text [[emph -]] messages, two fax [[emph -]] messages, and [[emph +]] one [[emph +]] voice [[emph -]] message.
  7957. This example emphasizes the words related to the number of messages and type of messages to help the listener discern the different kinds of information being presented.
  7958. Another common speaking technique that humans use is to pause before starting to speak about a new idea or before beginning a new paragraph. Adding an slnc (silence) command before beginning to speak a new idea or paragraph makes the synthetic voice sound like a person does when taking a breath in between ideas. This technique works best if you also raise the pitch range (using the pmod and pbas embedded commands) of the first sentence of the new paragraph. You must remember to lower the pitch range to achieve the desired effect.
  7959. [[emph -; pmod +1; pbas +1]] Good morning! [[pmod -1; pbas -1]]  This is a [[emph +]] newer [[emph -]] version of Apple's speech synthesis. The previous [[emph -]] version has already been [[emph -]] adopted by many developers. Users have sent us many positive [[emph +]] reports.
  7960.  
  7961. [[slnc 500; pmod +1; pbas +1]]
  7962. This newer [[emph -]] version has better signal [[emph -]] processing [[pmod -1; pbas -1]], new pitch [[emph -]] contours, and a new compression. It still doesn't [[emph -]] sound perfect, but people find it easier to understand.
  7963. This example deemphasizes the first word of the utterance, but raises the pitch to make the greeting sound more like a human would speak it. Then words are emphasized or deemphasized according to the techniques discussed previously. Silence is introduced before the new paragraph to signal a change in thought process. The pitch is raised and then lowered again after the first phrase. Note that you don’t have to wait a full sentence before changing the pitch back to its previous value. It’s best to work with these techniques until you find the most human-sounding utterances.
  7964. Phonemic Representation of Speech
  7965.  
  7966. The Speech Manager allows your application to process text phonemically. If your application speaks only text that the user writes, this feature is unlikely to be useful to you, because you cannot anticipate what the user might enter. However, if there are a few or many sentences that your application frequently converts into speech, it might be useful to represent parts of these sentences phonemically rather than textually.
  7967. It might be useful to convert your text into phonemes during application development in order to be able to reduce the amount of memory required to speak. If your application does not require the text-to-phoneme conversion portion of the speech synthesizer, significantly less RAM might be required to speak with some synthesizers.
  7968. Additionally, you might be able to use a higher quality text-to-phoneme conversion process (even one that does not work in real time) to generate precise phonemic information. This data can then be used with any speech synthesizer to produce better speech. For example, you might convert textual to phonemic data on a future version of the Speech Manager that performs such conversions more accurately than the Speech Manager currently does; that phonemic data could then be used to generate speech with any version of the Speech Manager. The Speech Manager’s TextToPhonemes function provides an easy method for converting text into its default phonemic equivalent.
  7969. To help the Speech Manager differentiate a textual representation of a word from a phonemic representation, you must embed commands in text that inform the Speech Manager to change into a mode in which it interprets a buffer of text as a phonemic representation of speech, in which particular combinations of letters represent particular phonemes. (You can also use the SetSpeechInfo function to change to phoneme mode.) To indicate to the Speech Manager that subsequent text is a phonemic representation of text to be spoken, embed the [[inpt PHON]] command within a string or buffer that your application passes to one of the SpeakString, SpeakText, or SpeakBuffer functions. To indicate that the Speech Manager should revert to textual interpretation of a text buffer, embed the [[inpt TEXT]] command. For example, passing the string
  7970. Hello, I am [[inpt PHON]]mAYkAXl[[inpt TEXT]], the talking computer.
  7971. to SpeakString, SpeakText, or SpeakBuffer would result in the generation of the sentence, “Hello, I am Michael, the talking computer.”
  7972. Some, but not all, speech synthesizers allow you to embed a command that causes the Speech Manager to interpret a buffer of text as a series of allophones.
  7973. Phonemic Symbols
  7974.  
  7975. Table 4-3 summarizes the set of standard phonemes recognized by American English speech synthesizers. Other languages and dialects require different phoneme inventories. Phonemes divide into two groups: vowels and consonants. All vowel symbols are pairs of uppercase letters. For simple consonants the symbol is that lowercase consonant; for blends and complex consonants, the symbol is in uppercase. Within the example words, the individual sounds being exemplified appear in boldface.
  7976. Table 4-3    American English phoneme symbols(continued)
  7977. Symbol    Example    Opcode    Symbol    Example    Opcode    
  7978. %    silence    0    D    them    21    
  7979. @    breath intake    1    f    fin    22    
  7980. AE    bat     2    g    gain    23    
  7981. EY    bait    3    h    hat    24    
  7982. AO    caught    4    J    jump    25    
  7983. AX    about     5    k    kin    26    
  7984. IY     beet     6    l    limb    27    
  7985. EH     bet     7    m    mat    28    
  7986.  
  7987. continued                        
  7988. IH      bit     8     n    nat    29    
  7989. AY     bite     9    N    tang    30    
  7990. IX     roses     10     p    pin    31    
  7991. AA     cot    11    r    ran    32    
  7992. UW     boot    12    s    sin    33    
  7993. UH    book    13     S    shin    34    
  7994. UX     bud     14     t    tin    35    
  7995. OW    boat     15     T    thin    36    
  7996. AW     bout     16     v    van    37    
  7997. OY     boy     17     w    wet    38    
  7998. b     bin     18     y    yet    39    
  7999. C     chin     19     z    zen    40    
  8000. d     din    20     Z    measure    41    
  8001.  
  8002. You can obtain information similar to that in Table 4-3 for whatever language a synthesizer supports by using the GetSpeechInfo function on a channel using the synthesizer with the soPhonemeSymbols selector. The information is returned in a phoneme descriptor record, whose structure is described on page 4-53.
  8003. Prosodic Control Symbols
  8004.  
  8005. The symbols listed in Table 4-4 are recognized as modifiers to the basic phonemes described in the preceding section. You can use them to more precisely control the quality of speech that is described in terms of raw phonemes.
  8006. Table 4-4    Prosodic control symbols(continued)
  8007. Type    Symbol    Symbol name    Description or illustration of effect        
  8008. Lexical stress:            Marks stress within a word (optional)        
  8009.   Primary stress    1        AEnt2IHsIXp1EYSAXn   (“anticipation”)        
  8010.   Secondary stress    2                
  8011. Syllable breaks:            Marks syllable breaks within a word (optional)        
  8012.   Syllable mark    =    (equal)    AEn=t2IH=sIX=p1EY=SAXn (“an-ti-ci-pa-tion”)        
  8013. Word prominence:            Placed before the affected word        
  8014.   Destressed    ~    (asciitilde)    Used for words with minimal informational content        
  8015.   Normal stress    _    (underscore)    Used for information-bearing words        
  8016.   Emphatic stress    +    (plus)    Used for words requiring special emphasis        
  8017. Prosodic:            Placed before the affected phoneme        
  8018.   Pitch rise    /    (slash)    Pitch will rise on the following phoneme        
  8019.   Pitch fall    \    (backslash)    Pitch will fall on the following phoneme        
  8020.   Lengthen   phoneme    >    (greater)    Lengthens the duration of the following phoneme        
  8021.   Shorten phoneme    <    (less)    Shortens the duration of the following phoneme        
  8022.  
  8023. Note
  8024. Note
  8025. Like all other phonemes, the “silence” phoneme (%) and the “breath intake” phoneme (@) can be lengthened or shortened using the > and < symbols.u
  8026. The prosodic control symbols (/, \, <, and >) can be concatenated to provide exaggerated or cumulative effects. The specific nature of the effect is dependent on the speech synthesizer. Speech synthesizers also often extend or enhance the controls described in the table.
  8027. Table 4-5 indicates the effect of punctuation marks on sentence prosody. In particular, the table shows the effect of punctuation marks on speech pitch and indicates to what extent the punctuation marks cause a pause. Note that because some languages might not use these punctuation marks, some synthesizers might not interpret them correctly. In general, speech synthesizers strive to mimic the pauses and changes in pitch of actual speakers in response to punctuation marks, so to obtain best results, you can punctuate according to standard grammatical rules.
  8028. Table 4-5    Effect of punctuation marks on English-language synthesizers(continued)
  8029. Symbol    Symbol name    Effect of punctuation mark    Effect on Timing    
  8030. &    (ampersand)    Forces no addition of silence between phonemes    No additional effect    
  8031. :    (colon)    End of clause, no change in pitch    Short pause follows    
  8032. ,    (comma)    Continuation rise in pitch    Short pause follows    
  8033. …    (ellipsis)    End of clause, no change in pitch    Pause follows    
  8034. !    (exclam)    End-of-sentence sharp fall in pitch    Pause follows    
  8035. -    (hyphen)    End of clause, no change in pitch    Short pause follows    
  8036. (    (parenleft)    Start reduced pitch range    Short pause precedes    
  8037.  
  8038. continued                
  8039. )    (parenright)    End reduced pitch range    Short pause follows    
  8040. .    (period)    End-of-sentence fall in pitch     Pause follows    
  8041. ?    (question)    End-of-sentence rise in pitch     Pause follows    
  8042. ‘    (quotedblleft, quotesingleleft)    Varies depending on context    Varies    
  8043. ’    (quotedblright, quotesingleright)    Varies depending on context    Varies    
  8044. ;    (semicolon)    Continuation rise in pitch    Short pause follows    
  8045.  
  8046. Specific pitch contours associated with these punctuation marks might vary according to other considerations in the analysis of the text. For example, if a question is rhetorical or begins with a word recognized by the synthesizer to be a question word, the pitch might fall at the question mark. Consequently the above effects should be regarded as only guidelines and not absolute. This also applies to the timing effects, which will vary according to the current rate setting.
  8047. Including Pronunciation Dictionaries 
  8048.  
  8049. No matter how sophisticated a speech synthesis system is, there will always be words that it does not automatically pronounce correctly. A clear instance of words that are often mispronounced is the class of proper nouns (names of people, place names, and so on). The Speech Manager supports pronunciation dictionaries which allow applications to override the default pronunciations of words. A pronunciation dictionary is a list of words along with their associated pronunciations stored in a resource of resource type 'dict'.
  8050. The application is free to store dictionaries in either the resource fork or the data fork of a file. The application is responsible for loading the individual dictionaries into RAM and then passing a handle to the dictionary data to the Speech Manager. The initial release of the Speech Manager, however, does not include any routines that can add entries to dictionaries or manipulate them in other ways. The Speech Manager does include a routine, the UseDictionary function, that you can use to install one or more pronunciation dictionaries in a speech channel.
  8051.  A multimedia application might store such a pronunciation dictionary resource in its own resource fork to specify the pronunciations of selected words used in a narration. A word-processing application, meanwhile, could allow a user to add words to a pronunciation dictionary stored in the resource fork of a text file. Or, a text-services application dedicated to speech generation might include large specialized dictionaries—for example, of medical terms—to specify pronunciation of words in particular subject areas. Because the Speech Manager allows your application to install as many pronunciation dictionaries as desired in a speech channel, it can use pronunciation dictionaries in one or more of these ways.
  8052. Note
  8053. The Dictionary Manager, described in Inside Macintosh: Text, cannot be used with pronunciation dictionaries. u
  8054. Whenever a speech synthesizer needs to determine the proper phonemic representation for a particular word, it first looks for the word in its pronunciation dictionaries. Pronunciation dictionary entries contain information that enables precise conversion between text and the correct phoneme codes, as described in “Phonemic Representation of Speech” beginning on page 4-32. Pronunciation dictionary entries also provide stress, intonation, and other information to help speech synthesizers produce more natural speech, as described in “Prosodic Control Symbols” beginning on page 4-34. Note that you cannot use punctuation marks (as described in Table 4-5) in pronunciation dictionaries.
  8055. A single pronunciation dictionary entry cannot be used to specify the pronunciation of an entire phrase, because the Speech Manager checks its pronunciation dictionary on a word-by-word basis. Thus, the textual portion of a pronunciation dictionary entry must not contain any spaces.
  8056. If the pronunciation dictionaries installed in a speech channel do not include an indication of how a word should be pronounced, then the Speech Manager uses its own pronunciation rules and internal dictionary to pronounce the words. In general, you need to create a dictionary only for unusual words that your application requires but the Speech Manager ordinarily pronounces incorrectly. You might also allow a user who is not pleased with the default pronunciation of a word to add the correct pronunciation to a pronunciation dictionary. You can create a dictionary using MPW Rez or another appropriate tool. See “The Pronunciation Dictionary Resource” beginning on page 4-89 for a discussion of the format of the pronunciation dictionary resource and the meaning of it fields.
  8057. To install a pronunciation dictionary resource in a speech channel, you must read the resource into memory and pass it to the UseDictionary function. Because the UseDictionary function requires that you specify a speech channel, you might need to reinstall the dictionary whenever your application allocates a new speech channel or whenever it resets an existing speech channel. Listing 4-9 shows how you can use the UseDictionary function to install a pronunciation dictionary resource in a speech channel.
  8058. Listing 4-9    Installing a pronunciation dictionary resource into a speech channel
  8059.  
  8060. PROCEDURE MyUseDictionary (chan: SpeechChannel; resID: Integer);
  8061. VAR
  8062.     myDict:                 Handle;                                            {handle to dictionary data}
  8063.     myErr:                 OSErr;
  8064. BEGIN
  8065.     myDict := GetResource('dict', resID);                                                            {load the dictionary}
  8066.     IF (myDict <> NIL) AND (ResError = noErr) THEN
  8067.     BEGIN
  8068.         myErr := UseDictionary(chan, myDict);                                                        {install the dictionary}
  8069.         IF myErr <> noErr THEN
  8070.             DoError(myErr);                                                    {respond to an error}
  8071.         ReleaseResource(myDict);                                                        {release the resource}
  8072.     END;
  8073. END;
  8074. The MyUseDictionary procedure defined in Listing 4-9 attempts to find a resource of resource type 'dict' with resource ID resID and uses the Resource Manager to read it into memory. If your application stores pronunciation dictionaries in the data fork of files, it can instead use analogous File Manager routines to read the data. If the data is read in correctly, MyUseDictionary calls the UseDictionary function to install the dictionary on the specified speech channel. Because the speech synthesizer copies all necessary data from the dictionary to its internal buffers, the application is free to release the memory occupied by the dictionary, as illustrated by the ReleaseResource call.
  8075. The pronunciation dictionary resource in Listing 4-10 consists of pronunciation dictionary entries in Rez format. Each entry specifies a word in textual format and its phonemic equivalent.
  8076. Listing 4-10    A sample pronunciation dictionary resource
  8077.  
  8078. resource 'dict' (1, "TestDict") {
  8079.     smRoman, langEnglish, verUS, ThisSecond,
  8080.     {
  8081.         pron, {tx, "ROOSEVELT",                                     ph, "_1EHf_d1IY_1AAr"},
  8082.         pron, {tx, "CHELSEA",                                     ph, "_C1EHls2IY"},
  8083.         pron, {tx, "AMHERST",                                     ph, "_2UXmAXrst"},
  8084.         pron, {tx, "REDSOX",                                     ph, "_r1EHd_s1AAks"},
  8085.         pron, {tx, "HALLOWEEN",                                     ph, "_h1AAl2OW_w1IYn"},
  8086.         pron, {tx, "FELIX",                                     ph, "_f1IYl2IHks_D2UX_k1AEt"},
  8087.         pron, {tx, "WEDNESDAY",                                     ph, "_m1IHd_w1IYk"},
  8088.     },
  8089. };
  8090. Note that you are not restricted to using pronunciations similar to those of the words listed. Typically, however, pronunciation dictionaries contain entries for words that the Speech Manager pronounces unsatisfactorily.
  8091. Also, note that a pronunciation dictionary’s entries need not be in any particular order. In particular, you should not assume that a pronunciation dictionary is in alphabetical order unless your application creates the dictionary and maintains that order.
  8092. The pronunciation dictionary resource header consists of nine fields, of which four must be explicitly defined in a Rez definition such as the one in Listing 4-10. The first three of these fields specify the script, language, and region code of the language for which the pronunciation dictionary is designed. Note that you must create a separate pronunciation dictionary for each region, language, or script. The fourth field of a pronunciation dictionary is the date the pronunciation dictionary was last modified, in terms of seconds since midnight, January 1, 1904. In Listing 4-10, it is assumed that the constant ThisSecond is defined to be such a date. For information on obtaining information about the current date in this format, see Inside Macintosh: Operating System Utilities. 
  8093.  
  8094. Speech Manager Reference
  8095.  
  8096. This section describes the constants, data structures, routines, and resources that are specific to the Speech Manager.
  8097. The section “Constants” describes the available speech information selectors.
  8098. The section “Data Structures” beginning on page 4-45 shows all of the Speech Manager’s Pascal data structures, including those for the voice specification and description records, the speech status information record, and the phoneme information and descriptor records.
  8099. The section “Speech Manager Routines” beginning on page 4-54 describes the Speech Manager functions that allow you to generate speech, use voices, manage and control speech channels, convert text to phonemes, and use pronunciation dictionaries.
  8100. The section “Application-Defined Routines” beginning on page 4-82 describes the kinds of callback procedures you can implement.
  8101. The section “Resources” beginning on page 4-89 describes the format of pronunciation dictionary resources.
  8102. Constants
  8103.  
  8104. This section describes the available speech information selectors.
  8105. Speech Information Selectors
  8106.  
  8107. This section describes the speech information selectors that you can pass in the selector parameter of the GetSpeechInfo and SetSpeechInfo functions.
  8108. CONST
  8109.     soCharacterMode                                = 'char';                {get or set character-processing mode}
  8110.     soCommandDelimiter                                = 'dlim';                {set embedded command delimiters}
  8111.     soCurrentA5                                = 'myA5';                {set A5 on callbacks}
  8112.     soCurrentVoice                                = 'cvox';                {set speaking voice}
  8113.     soErrorCallBack                                = 'ercb';                {set error callback}
  8114.     soErrors                                = 'erro';                {get error information}
  8115.     soInputMode                                = 'inpt';                {get or set text-processing mode}
  8116.     soNumberMode                                = 'nmbr';                {get or set number-processing mode}
  8117.     soPhonemeCallBack                                = 'phcb';                {set phoneme callback}
  8118.     soPhonemeSymbols                                = 'phsy';                {get phoneme symbols and example }
  8119.                                                     { words}
  8120.     soPitchBase                                = 'pbas';                {get or set baseline pitch}
  8121.     soPitchMod                                = 'pmod';                {get or set pitch modulation}
  8122.     soRate                                = 'rate';                {get or set speech rate}
  8123.     soRecentSync                                = 'sync';                {get most recent synchronization }
  8124.                                                     { message information}
  8125.     soRefCon                                = 'refc';                {set reference constant value}
  8126.     soReset                                = 'rset';                {set channel back to default state}
  8127.     soSpeechDoneCallBack                                = 'sdcb';                {set speech-done callback}
  8128.     soStatus                                = 'stat';                {get status of channel}
  8129.     soSyncCallBack                                = 'sycb';                {set synchronization callback}
  8130.     soSynthExtension                                = 'xtnd';                {get or set synthesizer-specific }
  8131.                                                     { information}
  8132.     soSynthType                                = 'vers';                {get synthesizer information}
  8133.     soTextDoneCallBack                                = 'tdcb';                {set text-done callback}
  8134.     soVolume                                = 'volm';                {get or set speech volume}
  8135.     soWordCallBack                                = 'wdcb';                {set word callback}
  8136. Constant descriptions
  8137. soCharacterMode
  8138. Get or set the speech channel’s character-processing mode. Two constants are currently defined for the processing mode, modeNormal and modeLiteral. When the character-processing mode is modeNormal, input characters are spoken as you would expect to hear them. When the mode is modeLiteral, each character is spoken literally, so that the word “cat” would be spoken “C–A–T”. The speechInfo parameter points to a variable of type OSType, which is the character-processing mode.
  8139.     This selector works with GetSpeechInfo and SetSpeechInfo and does not move memory.
  8140. soCommandDelimiter
  8141. Set the embedded speech command delimiter characters to be used for the speech channel. By default the opening delimiter is “[[” and the closing delimiter is “]]”. Your application might need to change these delimiters temporarily if those character sequences occur naturally in a text buffer that is to be spoken. Your application can also disable embedded command processing by passing empty delimiters (2 NIL bytes). The speechInfo parameter is a pointer to a delimiter information record, described on page 4-54.
  8142.     This selector works with the SetSpeechInfo function and does not move memory.
  8143. soCurrentA5    Set the value that the Speech Manager assigns to the A5 register before invoking any application-defined callback procedures for the speech channel. The A5 register must be set correctly if the callback procedures are to be able to access application global variables. For more information on the A5 register, see Inside Macintosh: Memory. The speechInfo parameter should be set to the pointer contained in the A5 register at a time when the application is not executing interrupt code or to NIL if your application wishes to clear a value previously set with the soCurrentA5 selector.
  8144.     This selector works with the SetSpeechInfo function and does not move memory. See Listing 4-6 on page 4-21 for an illustration of the use of this selector.
  8145. soCurrentVoice
  8146. Set the current voice on the current speech channel to the specified voice. The speechInfo parameter is a pointer to a voice specification record. Your application should create the record by calling the MakeVoiceSpec function, described on page 4-64. SetSpeechInfo will return an incompatibleVoice error if the specified voice is incompatible with the speech synthesizer associated with the speech channel. If you have a speech channel open using a voice from a particular synthesizer and you try to switch to a voice that works with a different synthesizer, you receive an incompatibleVoice error. You need to create a new channel to use with the new voice.
  8147.     This selector works with only SetSpeechInfo and might move memory. Your application should not invoke it at interrupt time.
  8148. soErrorCallBack
  8149. Set the callback procedure to be called when an error is encountered during the processing of an embedded command. The callback procedure might also be called if other conditions (such as insufficient memory) arise during the speech conversion process. When a Speech Manager function returns an error directly, the error callback procedure is not called. The callback procedure is passed information about the most recent error; it can determine information about the oldest pending error by using the speech information selector soErrors. The speechInfo parameter is a pointer to an application-defined error callback procedure, whose syntax is described on page 4-86. Passing NIL in speechInfo disables the error callback procedure.
  8150.     This selector works with the SetSpeechInfo function and does not move memory.
  8151. soErrors    Get saved error information for the speech channel and clear its error registers. This selector lets you poll for various run-time errors that occur during speaking, such as the detection of badly formed embedded commands. Errors returned directly by Speech Manager functions are not reported here. If your application defines an error callback procedure, the callback should use the soErrors selector to obtain error information. The speechInfo parameter is a pointer to a speech error information record, described on page 4-49.
  8152.     This selector works with the GetSpeechInfo function and does not move memory.
  8153. soInputMode    Get or set the speech channel’s current text-processing mode. The returned value specifies whether the channel is currently in text input mode or phoneme input mode. The speechInfo parameter is a pointer to a variable of type OSType, which specifies a text-processing mode. The following constants specify the available text-processing modes:
  8154.                     CONST
  8155.                         modeText                            = 'TEXT';
  8156.                         modePhonemes                            = 'PHON';
  8157.     The modeText constant indicates that the speech channel is in text-processing mode. The modePhonemes constant indicates that the speech channel is in phoneme-processing mode. When in phoneme-processing mode, a text buffer is interpreted to be a series of characters representing various phonemes and prosodic controls, as discussed in “Phonemic Representation of Speech” on page 4-32 and “Prosodic Control Symbols” on page 4-34. Some synthesizers might support additional input-processing modes and define constants for these modes.
  8158.     This selector works with both the GetSpeechInfo and SetSpeechInfo functions. It might move memory only when used in conjunction with the SetSpeechInfo function.
  8159. soNumberMode    Get or set the speech channel’s current number-processing mode. Two OSType constants are currently defined, modeNormal and modeLiteral. When the number-processing mode is modeNormal, the synthesizer assembles digits into numbers (so that 12 is spoken as “twelve”). When the mode is modeLiteral, each digit is spoken literally (so that 12 is spoken as “one, two”). The speechInfo parameter is a pointer to a variable of type OSType, which specifies the number-processing mode.
  8160.     This selector works with both the GetSpeechInfo and SetSpeechInfo functions and does not move memory.
  8161. soPhonemeCallBack
  8162. Set the callback procedure to be called every time the Speech Manager is about to generate a phoneme on the speech channel. The speechInfo parameter is a pointer to an application-defined phoneme callback procedure, whose syntax is described on page 4-87. Passing NIL in speechInfo disables the phoneme callback procedure.
  8163.     This selector works with the SetSpeechInfo function and does not move memory.
  8164. soPhonemeSymbols
  8165. Get a list of phoneme symbols and example words defined for the speech channel’s synthesizer. Your application might use this information to show the user what symbols to use when entering phonemic text directly. The speechInfo parameter is a pointer to a variable of type Handle that, on exit from the GetSpeechInfo function, is a handle to a phoneme descriptor record, described on page 4-53.
  8166.     This selector works with the GetSpeechInfo function and might move memory. Your application should not invoke it at interrupt time.
  8167. soPitchBase    Get or set the speech channel’s baseline speech pitch. This selector is intended for use by the Speech Manager; ordinarily, an application uses the GetSpeechPitch and SetSpeechPitch functions, described on page 4-75 and page 4-76, respectively. The speechInfo parameter is a pointer to a variable of type Fixed.
  8168.     This selector works with both the GetSpeechInfo and SetSpeechInfo functions and does not move memory.
  8169. soPitchMod    Get or set a speech channel’s pitch modulation. The speechInfo parameter is a pointer to a variable of type Fixed. Pitch modulation is also expressed as a fixed-point value in the range of 0.000 to 127.000. These values correspond to MIDI note values, where 60.000 is equal to middle C on a piano scale. The most useful speech pitches fall in the range of 40.000 to 55.000. A pitch modulation value of 0.000 corresponds to a monotone in which all speech is generated at the frequency corresponding to the speech pitch. Given a speech pitch value of 46.000, a pitch modulation of 2.000 would mean that the widest possible range of pitches corresponding to the actual frequency of generated text would be 44.000 to 48.000.
  8170.     This selector works with both the GetSpeechInfo and SetSpeechInfo functions and does not move memory.
  8171. soRate    Get or set a speech channel’s speech rate. The speechInfo parameter is a pointer to a variable of type Fixed. The possible range of speech rates is from 0.000 to 65535.65535. The range of supported rates is not predefined by the Speech Manager; each speech synthesizer provides its own range of speech rates. Average human speech occurs at a rate of 180 to 220 words per minute. 
  8172.     This selector works with both the GetSpeechInfo and SetSpeechInfo functions and does not move memory.
  8173. soRecentSync    Get the message code for the most recently encountered synchronization command. If no synchronization command has been encountered, 0 is returned. The speechInfo parameter is a pointer to a variable of type OSType.
  8174.     This selector works with the GetSpeechInfo function and does not move memory.
  8175. soRefCon    Set a speech channel’s reference constant value. The reference constant value is passed to application-defined callback procedures and might contain any value convenient for the application. The speechInfo parameter is a long integer containing the reference constant value. In contrast with other selectors, this selector does not require that the speechInfo parameter’s value be a pointer value. Typically, however, an application does use this selector to pass a pointer or handle value to callback procedures.
  8176.     This selector works with the SetSpeechInfo function and does not move memory. See Listing 4-6 on page 4-21 for an illustration of the use of this selector.
  8177. soReset    Set a speech channel back to its default state. For example, speech pitch and speech rate are set to default values. The speechInfo parameter should be set to NIL.
  8178.     This selector works with the SetSpeechInfo function and does not move memory.
  8179. soSpeechDoneCallBack
  8180. Set the callback procedure to be called when the Speech Manager has finished generating speech on the speech channel. The speechInfo parameter is a pointer to an application-defined speech-done callback procedure, whose syntax is described on page 4-84. Passing NIL in speechInfo disables the speech-done callback procedure.
  8181.     This selector works with the SetSpeechInfo function and does not move memory.
  8182. soStatus    Get a speech status information record for the speech channel. The speechInfo parameter is a pointer to a speech status information record, described on page 4-48.
  8183.     This selector works with the GetSpeechInfo function and does not move memory.
  8184. soSyncCallBack
  8185. Set the callback procedure to be called when the Speech Manager encounters a synchronization command within an embedded speech command in text being processed on the speech channel. The speechInfo parameter is a pointer to an application-defined synchronization callback procedure, whose syntax is described on page 4-85. Passing NIL in speechInfo disables the synchronization callback procedure.
  8186.     This selector works with the SetSpeechInfo function and does not move memory.
  8187. soSynthExtension
  8188. Get or set synthesizer-specific information or settings. The speechInfo parameter is a pointer to a speech extension data record, described on page 4-53. Your application should set the synthCreator field of this record before calling GetSpeechInfo or SetSpeechInfo. Ordinarily, your application must pass additional information to the synthesizer in the synthData field.
  8189.     This selector works with both the GetSpeechInfo and SetSpeechInfo functions. Whether it moves memory depends on the synthesizer being used and the information passed to the synthesizer.
  8190. soSynthType    Get a speech version information record for the speech synthesizer being used on the specified speech channel. The speechInfo parameter is a pointer to a speech version information record, described on page 4-50.
  8191.     This selector works with the GetSpeechInfo function and does not move memory. 
  8192. soTextDoneCallBack
  8193. Set the callback procedure to be called when the Speech Manager has finished processing speech being generated on the speech channel. The speechInfo parameter is a pointer to an application-defined text-done callback procedure, whose syntax is described on page 4-84. Passing NIL in speechInfo disables the text-done callback procedure.
  8194.     This selector works with the GetSpeechInfo function and does not move memory.
  8195. soVolume    Get or set the speech volume for a speech channel. The speechInfo parameter is a pointer to a variable of type Fixed. Volumes are expressed in fixed-point units ranging from 0.0 through 1.0. A value of 0.0 corresponds to silence, and a value of 1.0 corresponds to the maximum possible volume. Volume units lie on a scale that is linear with amplitude or voltage. A doubling of perceived loudness corresponds to a doubling of the volume.
  8196.     This selector works with both the GetSpeechInfo and SetSpeechInfo functions and does not move memory.
  8197. soWordCallBack
  8198. Set the callback procedure to be called every time the Speech Manager is about to generate a word on the speech channel. The speechInfo parameter is a pointer to an application-defined word callback procedure, whose syntax is described on page 4-87. Passing NIL in speechInfo disables the word callback procedure.
  8199.     This selector works with the SetSpeechInfo function and does not move memory. See Listing 4-7 on page 4-21 for an illustration of the use of this selector.
  8200. Data Structures
  8201.  
  8202. This section describes the data structures defined by the Speech Manager.
  8203. The speech channel record contains information internal to the Speech Manager. Speech channels, which process Speech Manager text and commands, are defined as pointers to Speech Manager records.
  8204. A voice specification record provides a unique specification of a voice. You can create such a record with the MakeVoiceSpec function and then pass it to the GetVoiceDescription function to obtain information about the voice. This information is contained in a voice description record. Or, you can use the GetVoiceInfo function to obtain information about the file that stores a voice. This information is contained in a voice file information record.
  8205. By using the GetSpeechInfo function, you can obtain information about a speech channel, as well as information about its synthesizer. Such information is returned in speech status information records, speech error information records, and speech version information records.
  8206. The GetSpeechInfo function also allows you to obtain information about the phonemes defined for a synthesizer. Information about a single phoneme is contained in a phoneme information record. A phoneme descriptor record contains phoneme information records for all of the phonemes that a synthesizer supports.
  8207. Synthesizers that use the GetSpeechInfo or SetSpeechInfo function to allow exploitation of synthesizer-specific features often require that data passed to it be formatted in a particular way. The speech extension data record allows your application to exchange data in any format with a synthesizer.
  8208. The SpeakString, SpeakText, and SpeakBuffer functions can process both text and commands embedded in that text. So that commands can be distinguished from text, the commands must be enclosed by command delimiters. The delimiter information record allows your application to change the command delimiters.
  8209. Voice Specification Records
  8210.  
  8211. A voice specification record provides a unique specification that you must use to obtain information about a voice. You also must use a voice specification record if you wish to create a speech channel that generates speech in a voice other than the current system default voice. The VoiceSpec data type defines a voice specification record. In Pascal, the VoiceSpecPtr data type defines a pointer to a voice specification record. The VoiceSpecPtr data type is not defined in the interface files for C programmers. If you are programming in C and you need to pass a variable of type VoiceSpecPtr to a Speech Manager routine, simply pass a pointer to a voice specification record instead.
  8212. TYPE VoiceSpec =
  8213. RECORD
  8214.     creator:                OSType;                    {ID of required synthesizer}
  8215.     id:                OSType;                    {ID of voice on the synthesizer}
  8216. END;
  8217. Field descriptions
  8218. creator    The synthesizer that is required to use the voice. This is equivalent to the value contained in the synthManufacturer field of a speech version information record and that contained in the synthCreator field of a speech extension data record. The set of OSType values specified entirely by space characters and lowercase letters is reserved.
  8219. id    The voice ID of the voice for the synthesizer. Every voice on a synthesizer has a unique ID.
  8220. IMPORTANT
  8221. IMPORTANT
  8222. To ensure compatibility with future versions of the Speech Manager, you should never fill in the fields of a voice specification record yourself. Instead, you should create a voice specification record by using the MakeVoiceSpec function.s
  8223. Voice Description Records
  8224.  
  8225. By calling the GetVoiceDescription function, you can obtain information about a voice in a voice description record. The VoiceDescription data type defines a voice description record.
  8226. TYPE VoiceDescription =
  8227. RECORD
  8228.     length:                LongInt;                {size of record}
  8229.     voice:                VoiceSpec;                {voice synthesizer and ID info}
  8230.     version:                LongInt;                {version number of voice}
  8231.     name:                Str63;                {name of voice}
  8232.     comment:                Str255;                {text information about voice}
  8233.     gender:                Integer;                {neuter, male, or female}
  8234.     age:                Integer;                {approximate age in years}
  8235.     script:                Integer;                {script code of text voice can process}
  8236.     language:                Integer;                {language code of voice output}
  8237.     region:                Integer;                {region code of voice output}
  8238.     reserved1:                LongInt;                {always 0--reserved for future use}
  8239.     reserved2:                LongInt;                {always 0--reserved for future use}
  8240.     reserved3:                LongInt;                {always 0--reserved for future use}
  8241.     reserved4:                LongInt;                {always 0--reserved for future use}
  8242. END;
  8243. Field descriptions
  8244. length    The size of the voice description record, in bytes.
  8245. voice    A voice specification record that uniquely identifies the voice.
  8246. version    The version number of the voice.
  8247. name    The name of the voice, preceded by a length byte. Names must be 63 characters or less.
  8248. comment    Additional text information about the voice. The information might indicate how much memory the voice requires. Some synthesizers use this field to store a phrase that can be spoken.
  8249. gender    The gender of the individual represented by the voice. The value in this field must be one of the following constants:
  8250.                     CONST
  8251.                         kNeuter                = 0;            {neuter voice}
  8252.                         kMale                = 1;            {male voice}
  8253.                         kFemale                = 2;            {female voice}
  8254.     A neuter voice is a voice that is not distinctively male or female.
  8255. age    The approximate age in years of the individual represented by the voice.
  8256. script    The script code of text that the voice can process.
  8257. language    A code that indicates the language of voice output.
  8258. region    A code that indicates the region represented by the voice.
  8259. reserved1    Reserved.
  8260. reserved2    Reserved.
  8261. reserved3    Reserved.
  8262. reserved4    The four reserved fields are reserved for use by Apple.
  8263. Voice File Information Records
  8264.  
  8265. A voice file information record specifies the file in which a voice is stored and the resource ID of the voice within that file. You can use the GetVoiceInfo function to obtain a voice file information record for a voice. The VoiceFileInfo data type defines a voice file information record. In Pascal, the VoiceFileInfoPtr data type defines a pointer to a voice file information record.
  8266. TYPE VoiceFileInfo =
  8267. RECORD
  8268.     fileSpec:                FSSpec;                {volume, dir, and name of file}
  8269.     resID:                 Integer;                {resource ID of voice in the file}
  8270. END;
  8271. Field descriptions
  8272. fileSpec    A file system specification record that contains the volume, directory, and name of the file containing the voice. Generally, files containing a single voice are of type kTextToSpeechVoiceFileType, and files containing multiple voices are of type kTextToSpeechVoiceBundleType.
  8273. resID    The resource ID of the voice in the file. Voices are stored in resources of type kTextToSpeechVoiceType.
  8274. Speech Status Information Records
  8275.  
  8276. By calling the GetSpeechInfo function with the soStatus selector, you can find out information about the status of a speech channel. This information is stored in a speech status information record, which the SpeechStatusInfo data type defines.
  8277. TYPE SpeechStatusInfo =
  8278. RECORD
  8279.     outputBusy:                        Boolean;                {TRUE if audio is playing }
  8280.                                             { or text is being processed}
  8281.     outputPaused:                        Boolean;                {TRUE if channel is paused}
  8282.     inputBytesLeft:                        LongInt;                {bytes of text left to process}
  8283.     phonemeCode:                        Integer;                {opcode for current phoneme}
  8284. END;
  8285. Field descriptions
  8286. outputBusy    Whether the speech channel is currently producing speech. A speech channel is considered to be producing speech even at some times when no audio data is being produced through the Macintosh speaker. This occurs, for example, when the Speech Manager is processing an input buffer but has not yet initiated speech or when speech output is paused.
  8287. outputPaused    Whether speech output in the speech channel has been paused by a call to the PauseSpeechAt function.
  8288. inputBytesLeft
  8289. The number of input bytes of the text that the speech channel must still process. When inputBytesLeft is 0, the buffer of input text passed to one of the SpeakText or SpeakBuffer functions may be disposed of. (Note that when you call the SpeakString function, the Speech Manager stores a duplicate of the string to be spoken in an internal buffer; thus, you may delete the original string immediately after calling SpeakString.)
  8290. phonemeCode    The opcode for the phoneme that the speech channel is currently processing.
  8291. Speech Error Information Records
  8292.  
  8293. By calling the GetSpeechInfo function with the soErrors selector, you can obtain a speech error information record, which shows what Speech Manager errors occurred while processing a text buffer on a given speech channel. The SpeechErrorInfo data type defines a speech error information record.
  8294. TYPE SpeechErrorInfo =
  8295. RECORD
  8296.     count:                Integer;                    {number of errors since last check}
  8297.     oldest:                OSErr;                    {oldest unread error}
  8298.     oldPos:                LongInt;                    {character position of oldest error}
  8299.     newest:                OSErr;                    {most recent error}
  8300.     newPos:                LongInt;                    {character position of newest error}
  8301. END;
  8302. Field descriptions
  8303. Field descriptions
  8304. count    The number of errors that have occurred in processing the current text buffer since the last call to the GetSpeechInfo function with the soErrors selector. Of these errors, you can find information about only the first and last error that occurred.
  8305. oldest    The error code of the first error that occurred after the previous call to the GetSpeechInfo function with the soErrors selector.
  8306. oldPos    The character position within the text buffer being processed of the first error that occurred after the previous call to the GetSpeechInfo function with the soErrors selector.
  8307. newest    The error code of the most recent error.
  8308. newPos    The character position within the text buffer being processed of the most recent error.
  8309. Speech error information records never include errors that are returned by Speech Manager routines. Instead, they reflect only errors encountered directly in the processing of text, and, in particular, in the processing of commands embedded within text.
  8310. The speech error information record keeps track of only the most recent error and the first error that occurred after the previous call to the GetSpeechInfo function with the soErrors selector. If your application needs to keep track of all errors, then you should install an error callback procedure, as described in “Error Callback Procedure” beginning on page 4-86.
  8311. Speech Version Information Records
  8312.  
  8313. By calling the GetSpeechInfo function with the soSynthType selector, you can obtain a speech version information record, which provides information about the speech synthesizer currently being used. The SpeechVersionInfo data type defines a speech version information record.
  8314. TYPE SpeechVersionInfo =
  8315. RECORD
  8316.     synthType:                            OSType;                    {general synthesizer type}
  8317.     synthSubType:                            OSType;                    {specific synthesizer type}
  8318.     synthManufacturer:                            OSType;                    {synthesizer creator ID}
  8319.     synthFlags:                            LongInt;                    {synthesizer feature flags}
  8320.     synthVersion:                            NumVersion;                    {synthesizer version number}
  8321. END;
  8322. Field descriptions
  8323. synthType    The general type of the synthesizer. For the current version of the Speech Manager, this field always contains the value kTextToSpeechSynthType, indicating that the synthesizer converts text into speech.
  8324. synthSubType    The specific type of the synthesizer. Currently, no specific types of synthesizer are defined. If you define a new type of synthesizer, you should register the four-character code for your type with Developer Technical Support.
  8325. synthManufacturer
  8326. A unique identification of a synthesizer engine. If you develop synthesizers, then you should register a different four-character code for each synthesizer you develop with Developer Technical Support. The creatorID field of the voice specification record and the synthCreator field of a speech extension data record should each be set to the value stored in this field for the desired synthesizer.
  8327. synthFlags    A set of flags indicating which synthesizer features are activated. The following constants define the bits in this field whose meanings are defined for all synthesizers:
  8328.                     CONST
  8329.                         kNoEndingProsody                            = 1;
  8330.                         kNoSpeechInterrupt                            = 2;
  8331.                         kPreflightThenPause                            = 4;
  8332.     The kNoEndingProsody flag bit is used to control whether or not the speech synthesizer automatically applies ending prosody, the speech tone and cadence that normally occur at the end of a statement. Under normal circumstances (for example, when the flag bit is not set), ending prosody is applied to the speech when the end of the textBuf data is reached. This default behavior can be disabled by setting the kNoEndingProsody flag bit.
  8333.     Some synthesizers do not speak until the kNoEndingProsody flag bit is reset, or they encounter a period in the text, or textBuf is full.
  8334.     The kNoSpeechInterrupt flag bit is used to control the behavior of SpeakBuffer when called on a speech channel that is still busy. When the flag bit is not set, SpeakBuffer behaves similarly to SpeakString and SpeakText. Any speech currently being produced on the specified speech channel is immediately interrupted, and then the new text buffer is spoken. When the kNoSpeechInterrupt flag bit is set, however, a request to speak on a channel that is still busy processing a prior text buffer will result in an error. The new buffer is ignored and the error synthNotReady is returned. If the prior text buffer has been fully processed, the new buffer is spoken normally. One way of achieving continuous speech without using callback procedures is to continually call SpeakBuffer with the kNoSpeechInterrupt flag bit set until the function returns noErr. The function will then execute as soon as the first text buffer has been processed.
  8335.     The kPreflightThenPause flag bit is used to minimize the latency experienced when the speech synthesizer is attempting to speak. Ordinarily, whenever a call to SpeakString, SpeakText, or SpeakBuffer is made, the speech synthesizer must perform a certain amount of initial processing before speech output is heard. This startup latency can vary from a few milliseconds to several seconds depending upon which speech synthesizer is being used. Recognizing that larger startup delays might be detrimental to certain applications, a mechanism is provided to allow the synthesizer to perform any necessary computations at noncritical times. Once the computations have been completed, the speech is able to start instantly. When the kPreflightThenPause flag bit is set, the speech synthesizer will process the input text as necessary to the point where it is ready to begin producing speech output. At this point, the synthesizer will enter a paused state and return to the caller. When the application is ready to produce speech, it should call the ContinueSpeech function to begin speaking. 
  8336. synthVersion    The version number of the synthesizer.
  8337. Phoneme Information Records
  8338.  
  8339. Information about a phoneme is stored in a phoneme information record. Ordinarily, you use a phoneme information record to show the user how to enter text to represent a particular phoneme when the 'PHON' input mode is activated. The PhonemeInfo data type defines a phoneme information record.
  8340. TYPE PhonemeInfo =
  8341. RECORD
  8342.     opCode:                    Integer;                {opcode for the phoneme}
  8343.     phStr:                    Str15;                {corresponding character string}
  8344.     exampleStr:                    Str31;                {word that shows use of phoneme}
  8345.     hiliteStart:                    Integer;                {offset from beginning of word }
  8346.                                         { to beginning of phoneme sound}
  8347.     hiliteEnd:                    Integer;                {offset from beginning of word }
  8348.                                         { to end of phoneme sound}
  8349. END;
  8350. Field descriptions
  8351. opCode    The opcode for the phoneme. For a list of English-language opcodes, see Table 4-3 on page 4-33.
  8352. phStr    The string used to represent the phoneme. The string does not necessarily have a phonetic connection to the phoneme, but might simply be an abstract textual representation of it.
  8353. exampleStr    An example word that illustrates use of the phoneme.
  8354. hiliteStart    The number of characters in the example word that precede the portion of that word representing the phoneme. 
  8355. hiliteEnd    The number of characters between the beginning of the example word and the end of the portion of that word representing the phoneme.
  8356. You might use the information contained in the hiliteStart and hiliteEnd fields to highlight the characters in the example word that represent the phoneme.
  8357. Note that in order to obtain a phoneme information record for an individual phoneme, you must obtain a list of phonemes through a phoneme descriptor record, described next.
  8358. Phoneme Descriptor Records
  8359.  
  8360. By calling the GetSpeechInfo function with the soPhonemeSymbols selector, you can obtain a phoneme descriptor record, which describes all phonemes defined for the current synthesizer. The PhonemeDescriptor data type defines a phoneme descriptor record.
  8361. TYPE PhonemeDescriptor =
  8362. RECORD
  8363.     phonemeCount:                        Integer;                {number of phonemes defined by current }
  8364.                                             { synthesizer}
  8365.     thePhonemes:                        ARRAY[0..0] OF PhonemeInfo;                                        
  8366.                                             {list of phoneme information records}
  8367. END;
  8368. Field descriptions
  8369. phonemeCount    The number of phonemes that the current synthesizer defines. Typically, this will correspond to the number of phonemes in the language supported by the synthesizer.
  8370. thePhonemes    An array of phoneme information records.
  8371. A common use for a phoneme descriptor record is to provide a graphical display to the user of all available phonemes. Note that such a list would be useful only for a user entering phonemic data directly rather than just entering text.
  8372. Speech Extension Data Records
  8373.  
  8374. The speech extension data record allows you to use the GetSpeechInfo and SetSpeechInfo functions with selectors defined by particular synthesizers. By requiring that you pass to one of these functions a pointer to a speech extension data record, synthesizers can permit the exchange of data in any format. The SpeechXtndData data type defines a speech extension data record.
  8375. TYPE SpeechXtndData =
  8376. RECORD
  8377.     synthCreator:                        OSType;                {synthesizer creator ID}
  8378.                                             {data used by synthesizer}
  8379.     synthData:                        PACKED ARRAY[0..1] OF Char;
  8380. END;
  8381. Field descriptions
  8382. synthCreator    The synthesizer’s creator ID, identical to the value stored in the synthManufacturer field of a speech version information record. Field descriptions
  8383. You should set this field to the appropriate value before calling GetSpeechInfo or SetSpeechInfo.
  8384. synthData    Synthesizer-specific data. The size and format of the data in this field may vary.
  8385. Delimiter Information Records
  8386.  
  8387. A delimiter information record defines the characters used to indicate the beginning and end of a command embedded in text. A delimiter can be one or two characters. The DelimiterInfo data type defines a delimiter information record.
  8388. TYPE DelimiterInfo =
  8389. RECORD
  8390.     startDelimiter:                        PACKED ARRAY[0..1] OF Char;
  8391.     endDelimiter:                        PACKED ARRAY[0..1] OF Char;
  8392. END;
  8393. Field descriptions
  8394. startDelimiter    The start delimiter for an embedded command. By default, the start delimiter is “[[”.
  8395. endDelimiter    The end delimiter for an embedded command. By default, the end delimiter is “]]”.
  8396. Ordinarily, applications that support embedded speech commands should not change the start or end delimiters. However, if for some reason you must change the delimiters, you can use the SetSpeechInfo function with the soCommandDelimiter selector. For example, you might do this if a text buffer naturally includes the delimiter strings. Before passing such a buffer to the Speech Manager, you can change the delimiter strings to some two-character sequences not used in the buffer and then change the delimiter strings back once processing of the buffer is complete.
  8397. If a single-byte delimiter is desired, it should be followed by a NIL (0) byte. If the delimiter strings both consist of two NIL bytes, embedded command processing is disabled.
  8398. Speech Manager Routines
  8399.  
  8400. This section describes the routines provided by the Speech Manager. You can use these routines to
  8401. n    generate speech and then pause or stop it
  8402. n    obtain information about an individual voice or all voices
  8403. n    create and dispose of speech channels
  8404. n    obtain the Speech Manager’s version and status
  8405. n    change the rate or pitch of speech
  8406. n    convert textual into phonetic data
  8407. n    install a pronunciation dictionary into a speech channel
  8408. With the exception of the SpeechManagerVersion, SpeechBusy, and SpeechBusySystemWide functions, all Speech Manager routines return a result code to indicate whether an error has occurred.
  8409. The section “Application-Defined Routines” beginning on page 4-82 describes the syntax and operation of application-defined callback procedures.
  8410. Starting, Stopping, and Pausing Speech
  8411.  
  8412. You can use the SpeakString function to generate speech from strings of fewer than 256 characters. The SpeakText function also generates speech, but through a speech channel through which you can exert control over the generated speech. The SpeakBuffer function includes all the capabilities of SpeakText and allows you to set certain flags that control speech behavior.
  8413. To stop speech, use the StopSpeech function or the StopSpeechAt function. The latter provides control over when speech is stopped. To pause and later resume speech, use the PauseSpeechAt and ContinueSpeech functions.
  8414. SpeakString
  8415.  
  8416. You can use the SpeakString function to have the Speech Manager speak a text string.
  8417. FUNCTION SpeakString (s: Str255): OSErr;
  8418. s    The string to be spoken.
  8419. DESCRIPTION
  8420. The SpeakString function attempts to speak the Pascal-style text string contained in the string s. Speech is produced asynchronously using the default system voice. When an application calls this function, the Speech Manager makes a copy of the passed string and creates any structures required to speak it. As soon as speaking has begun, control is returned to the application. The synthesized speech is generated asynchronously to the application so that normal processing can continue while the text is being spoken. No further interaction with the Speech Manager is required at this point, and the application is free to release the memory that the original string occupied.
  8421. If SpeakString is called while a prior string is still being spoken, the sound currently being synthesized is interrupted immediately. Conversion of the new text into speech is then begun. If you pass a zero-length string (or, in C, a null pointer) to SpeakString, the Speech Manager stops any speech previously being synthesized by SpeakString without generating additional speech. If your application uses SpeakString, it is often a good idea to stop any speech in progress whenever your application receives a suspend event. (Note, however, that calling SpeakString with a zero-length string has no effect on speech channels other than the one managed internally by the Speech Manager for the SpeakString function.)
  8422. The text passed to the SpeakString function may contain embedded speech commands.
  8423. SPECIAL CONSIDERATIONS
  8424. Because the SpeakString function moves memory, you should not call it at interrupt time.
  8425. ASSEMBLY-LANGUAGE INFORMATION
  8426. The trap macro and routine selector for the SpeakString function are
  8427. Trap macro    Selector    
  8428. _SoundDispatch    $0220000C    
  8429.  
  8430. RESULT CODESnoErr    0    No error    
  8431. memFullErr    –108    Not enough memory to speak    
  8432. synthOpenFailed    –241    Could not open another speech synthesizer channel    
  8433.  
  8434. SpeakText
  8435.  
  8436. You can use the SpeakText function to have the Speech Manager speak a buffer of text.
  8437. FUNCTION SpeakText (chan: SpeechChannel; textBuf: Ptr; 
  8438.                             textBytes: LongInt): OSErr;
  8439. chan    The speech channel through which speech is to be spoken.
  8440. textBuf    A pointer to the first byte of text to spoken.
  8441. textBytes    The number of bytes of text to spoken.
  8442. DESCRIPTION
  8443. The SpeakText function converts the text stream specified by the textBuf and textBytes parameters into speech using the voice and control settings for the speech channel chan, which should be created with the NewSpeechChannel function. The speech is generated asynchronously. This means that control is returned to your application before the speech has finished (and probably even before it has begun). The maximum length of the text buffer that can be spoken is limited only by the available RAM.
  8444. If SpeakText is called while the channel is currently busy speaking the contents of a prior text buffer, it immediately stops speaking from the prior buffer and begins speaking from the new text buffer as soon as possible. If you pass a zero-length string (or, in C, a null pointer) to SpeakText, the Speech Manager stops all speech currently being synthesized by the speech channel specified in the chan parameter without generating additional speech.
  8445. sWARNING
  8446. The text buffer must be locked in memory and must not move while the Speech Manager processes it. This buffer is read at interrupt time, and moving it could cause a system crash. If your application defines a text-done callback procedure, then it can move the text buffer or dispose of it once the callback procedure is executed.s
  8447. SPECIAL CONSIDERATIONS
  8448. Because the SpeakText function moves memory, you should not call it at interrupt time.
  8449. ASSEMBLY-LANGUAGE INFORMATION
  8450. The trap macro and routine selector for the SpeakText function are
  8451. Trap macro    Selector    
  8452. _SoundDispatch    $0624000C    
  8453.  
  8454. RESULT CODESnoErr    0    No error    
  8455. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8456.  
  8457. SpeakBuffer
  8458.  
  8459. You can use the SpeakBuffer function to have the Speech Manager speak a buffer of text, using certain flags to control speech behavior.
  8460. FUNCTION SpeakBuffer (chan: SpeechChannel; textBuf: Ptr; 
  8461.                                 textBytes: LongInt; 
  8462.                                 controlFlags: LongInt): OSErr;
  8463. chan    The speech channel through which speech is to be spoken.
  8464. textBuf    A pointer to the first byte of text to spoken.
  8465. textBytes    The number of bytes of text to spoken.
  8466. controlFlags
  8467. Control flags to customize speech behavior.
  8468. DESCRIPTION
  8469. The SpeakBuffer function behaves identically to the SpeakText function, but allows control of several speech parameters by setting values of the controlFlags parameter. The controlFlags parameter relies on the following constants, which may be applied additively:
  8470. CONST
  8471.     kNoEndingProsody                                = 1;        {disable prosody at end of sentences}
  8472.     kNoSpeechInterrupt                                = 2;        {do not interrupt current speech}
  8473.     kPreflightThenPause                                = 4;        {compute speech without generating}
  8474. Each constant specifies a flag bit of the controlFlags parameter, so by passing the constants additively you can enable multiple capabilities of SpeakBuffer. If you pass 0 in the controlFlags parameter, SpeakBuffer works just like SpeakText. By passing kNoEndingProsody + kNoSpeechInterrupt in the controlFlags parameter, SpeakBuffer works like SpeakText except that the kNoEndingProsody and kNoSpeechInterrupt features have been selected. Future versions of the Speech Manager may define additional constants. 
  8475. The kNoEndingProsody flag bit is used to control whether or not the speech synthesizer automatically applies ending prosody, the speech tone and cadence that normally occur at the end of a statement. Under normal circumstances (for example, when the flag bit is not set), ending prosody is applied to the speech when the end of the textBuf data is reached. This default behavior can be disabled by setting the kNoEndingProsody flag bit.
  8476. Some synthesizers do not speak until the kNoEndingProsody flag bit is reset, or they encounter a period in the text, or textBuf is full.
  8477. The kNoSpeechInterrupt flag bit is used to control the behavior of SpeakBuffer when called on a speech channel that is still busy. When the flag bit is not set, SpeakBuffer behaves similarly to SpeakString and SpeakText. Any speech currently being produced on the specified speech channel is immediately interrupted, and then the new text buffer is spoken. When the kNoSpeechInterrupt flag bit is set, however, a request to speak on a channel that is still busy processing a prior text buffer will result in an error. The new buffer is ignored and the error synthNotReady is returned. If the prior text buffer has been fully processed, the new buffer is spoken normally. One way of achieving continuous speech without using callback procedures is to continually call SpeakBuffer with the kNoSpeechInterrupt flag bit set until the function returns noErr. The function will then execute as soon as the first text buffer has been processed.
  8478. The kPreflightThenPause flag bit is used to minimize the latency experienced when the speech synthesizer is attempting to speak. Ordinarily, whenever a call to SpeakString, SpeakText, or SpeakBuffer is made, the speech synthesizer must perform a certain amount of initial processing before speech output is heard. This startup latency can vary from a few milliseconds to several seconds depending upon which speech synthesizer is being used. Recognizing that larger startup delays might be detrimental to certain applications, a mechanism exists to allow the synthesizer to perform any necessary computations at noncritical times. Once the computations have been completed, the speech is able to start instantly. When the kPreflightThenPause flag bit is set, the speech synthesizer will process the input text as necessary to the point where it is ready to begin producing speech output. At this point, the synthesizer will enter a paused state and return to the caller. When the application is ready to produce speech, it should call the ContinueSpeech function to begin speaking.
  8479. When the controlFlags parameter is set to 0, SpeakBuffer behaves identically to SpeakText.
  8480. SPECIAL CONSIDERATIONS
  8481. Because the SpeakBuffer function might move memory, you should not call it at interrupt time.
  8482. ASSEMBLY-LANGUAGE INFORMATION
  8483. The trap macro and routine selector for the SpeakBuffer function are
  8484. Trap macro    Selector    
  8485. _SoundDispatch    $0828000C    
  8486.  
  8487. RESULT CODESnoErr    0    No error    
  8488. synthNotReady    –242    Speech channel is still busy speaking    
  8489. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8490.  
  8491. StopSpeech
  8492.  
  8493. You can use the StopSpeech function to terminate speech immediately on a specified channel.
  8494. FUNCTION StopSpeech (chan: SpeechChannel): OSErr;
  8495. chan    The speech channel on which speech is to be stopped.
  8496. DESCRIPTION
  8497. The StopSpeech function immediately terminates speech on the channel specified by the chan parameter. After returning from StopSpeech, your application can safely release any text buffer that the speech synthesizer has been using. You can call StopSpeech for an already idle channel without ill effect.
  8498. You can also stop speech by passing a zero-length string (or, in C, a null pointer) to one of the SpeakString, SpeakText, or SpeakBuffer functions. Doing this stops speech only in the specified speech channel (or, in the case of SpeakString, in the speech channel managed internally by the Speech Manager).
  8499. SPECIAL CONSIDERATIONS
  8500. Because the StopSpeech function might move or purge memory, you should not call it at interrupt time.
  8501. ASSEMBLY-LANGUAGE INFORMATION
  8502. The trap macro and routine selector for the StopSpeech function are
  8503. Trap macro    Selector    
  8504. _SoundDispatch    $022C000C    
  8505.  
  8506. RESULT CODESnoErr    0    No error    
  8507. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8508.  
  8509. SEE ALSO
  8510. Before calling the StopSpeech function, you can use the SpeechBusy function, which is described on page 4-72, to determine if a synthesizer is still speaking. If you are working with multiple speech channels, you can use the status selector with the routine GetSpeechInfo which is described on page 4-77, to determine if a specific channel is still speaking.
  8511. StopSpeechAt
  8512.  
  8513. You can use the StopSpeechAt function to terminate speech delivery on a specified channel either immediately or at the end of the current word or sentence.
  8514. FUNCTION StopSpeechAt (chan: SpeechChannel; whereToStop: LongInt)
  8515.                                 : OSErr;
  8516. chan    The speech channel on which speech is to be stopped.
  8517. whereToStop
  8518. A constant indicating when speech processing should stop. Pass the constant kImmediate to stop immediately, even in the middle of a word. Pass kEndOfWord or kEndOfSentence to stop speech at the end of the current word or sentence, respectively.
  8519. DESCRIPTION
  8520. The StopSpeechAt function halts the production of speech on the channel specified by chan at a specified point in the text. This routine returns immediately, although speech output continues until the specified point has been reached.
  8521. sWARNING
  8522. If you call the StopSpeechAt function before the Speech Manager finishes processing input text, then the function might return before some input text has yet to be spoken. Thus, before disposing of the text buffer, your application should wait until its text-done callback procedure has been called (if one has been defined), or until it can determine (by, for example obtaining a speech status information record) that the Speech Manager is no longer processing input text.s
  8523. If the end of the input text buffer is reached before the specified stopping point, the speech synthesizer stops at the end of the buffer without generating an error.
  8524. SPECIAL CONSIDERATIONS
  8525. Because the StopSpeechAt function might move or purge memory, you should not call it at interrupt time.
  8526. ASSEMBLY-LANGUAGE INFORMATION
  8527. The trap macro and routine selector for the StopSpeechAt function are
  8528. Trap macro    Selector    
  8529. _SoundDispatch    $0430000C    
  8530.  
  8531. RESULT CODESnoErr    0    No error    
  8532. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8533.  
  8534. PauseSpeechAt
  8535.  
  8536. You can use the PauseSpeechAt function to pause speech on a speech channel.
  8537. FUNCTION PauseSpeechAt (chan: SpeechChannel; whereToStop: LongInt)
  8538.                                 : OSErr;
  8539. chan    The speech channel on which speech is to be paused.
  8540. whereToStop
  8541. A constant indicating when speech processing should be paused. Pass the constant kImmediate to pause immediately, even in the middle of a word. Pass kEndOfWord or kEndOfSentence to pause speech at the end of the current word or sentence, respectively.
  8542. DESCRIPTION
  8543. The PauseSpeechAt function makes speech production pause at a specified point in the text. PauseSpeechAt returns immediately, although speech output will continue until the specified point.
  8544. You can determine whether your application has paused speech output on a speech channel by obtaining a speech status information record through the GetSpeechInfo function. While a speech channel is paused, the speech status information record indicates that outputBusy and outputPaused are both TRUE.
  8545. If the end of the input text buffer is reached before the specified pause point, speech output pauses at the end of the buffer.
  8546. The PauseSpeechAt function differs from the StopSpeech and StopSpeechAt functions in that a subsequent call to ContinueSpeech, described next, causes the contents of the current text buffer to continue being spoken.
  8547. sWARNING
  8548. If you plan to continue speech synthesis from a paused speech channel, the text buffer being processed must remain available at all times and must not move while the channel is in a paused state. s
  8549. SPECIAL CONSIDERATIONS
  8550. Because the PauseSpeechAt function might move or purge memory, you should not call it at interrupt time.
  8551. ASSEMBLY-LANGUAGE INFORMATION
  8552. The trap macro and routine selector for the PauseSpeechAt function are
  8553. Trap macro    Selector    
  8554. _SoundDispatch    $0434000C    
  8555.  
  8556. RESULT CODESnoErr    0    No error    
  8557. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8558.  
  8559. ContinueSpeech
  8560.  
  8561. You can use the ContinueSpeech function to resume speech paused by the PauseSpeechAt function.
  8562. FUNCTION ContinueSpeech (chan: SpeechChannel): OSErr;
  8563. chan    The paused speech channel on which speech is to be resumed.
  8564. DESCRIPTION
  8565. At any time after the PauseSpeechAt function is called, the ContinueSpeech function can be called to continue speaking from the beginning of the word in which speech paused. Calling ContinueSpeech on a channel that is not currently in a paused state has no effect on the speech channel or on future calls to the PauseSpeechAt function. If you call ContinueSpeech on a channel before a pause is effective, ContinueSpeech cancels the pause.
  8566. If the PauseSpeechAt function stopped speech in the middle of a word, the Speech Manager will start speaking that word from the beginning when you call ContinueSpeech.
  8567. SPECIAL CONSIDERATIONS
  8568. Because the ContinueSpeech function moves memory, you should not call it at interrupt time.
  8569. ASSEMBLY-LANGUAGE INFORMATION
  8570. The trap macro and routine selector for the ContinueSpeech function are
  8571. Trap macro    Selector    
  8572. _SoundDispatch    $0238000C    
  8573.  
  8574. RESULT CODESnoErr    0    No error    
  8575. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8576.  
  8577. Obtaining Information About Voices
  8578.  
  8579. Specification of a voice requires a voice specification record. When you already know the creator and ID for a voice, you should use the MakeVoiceSpec function to create such a record rather than filling in the fields of one directly. To obtain information about all available voices, use the CountVoices function to determine how many voices are available, and the GetIndVoice function to obtain a voice specification record corresponding to each voice.
  8580. Having created a voice specification record, you can obtain information about the voice to which it corresponds. The GetVoiceDescription function provides information about a voice in the form of a voice description record. In addition to duplicating the capabilities of the GetVoiceDescription function, the GetVoiceInfo function allows you to obtain information about where on disk a voice is stored.
  8581. MakeVoiceSpec
  8582.  
  8583. To set the fields of a voice specification record, you should use the MakeVoiceSpec function. You should never set the fields of such a record directly.
  8584. FUNCTION MakeVoiceSpec (creator: OSType; id: OSType; 
  8585.                                     voice: VoiceSpecPtr): OSErr;
  8586. creator    The ID of the synthesizer that your application requires.
  8587. id    The ID of the voice on the synthesizer specified by the creator parameter.
  8588. voice    A pointer to the voice specification record whose fields are to be filled in.
  8589. DESCRIPTION
  8590. A voice specification record is a unique voice ID used by the Speech Manager. Most voice management routines expect to be passed a pointer to a voice specification record. When you already know the creator and ID for a voice, you should use the MakeVoiceSpec function to create such a record rather than filling in the fields of one directly. On exit, the voice specification record pointed to by the voice parameter contains the appropriate values.
  8591. SPECIAL CONSIDERATIONS
  8592. You can call the MakeVoiceSpec function at interrupt time.
  8593. ASSEMBLY-LANGUAGE INFORMATION
  8594. The trap macro and routine selector for the MakeVoiceSpec function are
  8595. Trap macro    Selector    
  8596. _SoundDispatch    $0604000C    
  8597.  
  8598. RESULT CODESnoErr    0    No error    
  8599.  
  8600. CountVoices
  8601.  
  8602. You can determine how many voices are available by calling the CountVoices function.
  8603. FUNCTION CountVoices (VAR numVoices: Integer): OSErr;
  8604. numVoices    On exit, the number of voices that the application can use.
  8605. DESCRIPTION
  8606. The CountVoices function returns, in the numVoices parameter, the number of voices available. The application can then use this information to call the GetIndVoice function, described next, to obtain voice specification records for one or more of the voices.
  8607. Each time CountVoices is called, the Speech Manager searches for new voices.
  8608. SPECIAL CONSIDERATIONS
  8609. Because the CountVoices function moves memory, you should not call it at interrupt time.
  8610. ASSEMBLY-LANGUAGE INFORMATION
  8611. The trap macro and routine selector for the CountVoices function are
  8612. Trap macro    Selector    
  8613. _SoundDispatch    $0108000C    
  8614.  
  8615. RESULT CODESnoErr    0    No error    
  8616.  
  8617. GetIndVoice
  8618.  
  8619. You can obtain a voice specification record for a voice by passing an index to the GetIndVoice function.
  8620. FUNCTION GetIndVoice (index: Integer; voice: VoiceSpecPtr): OSErr;
  8621. index    The index of the voice for which to obtain a voice specification record. This number must range from 1 to the total number of voices, as returned by the CountVoices function.
  8622. voice    A pointer to the voice specification record whose fields are to be filled in.
  8623. DESCRIPTION
  8624. The GetIndVoice function returns, in the voice specification record pointed to by the voice parameter, a specification of the voice whose index is provided in the index parameter. Your application should make no assumptions about the order in which voices are indexed.
  8625. sWARNING
  8626. sWARNING
  8627. Your application should not add, remove, or modify a voice and then call the GetIndVoice function with an index value other than 1. To allow the Speech Manager to update its information about voices, your application should always either call the CountVoices function or call the GetIndVoice function with an index value of 1 after adding, removing, or modifying a voice or after a time at which the user might have done so.s
  8628. If you specify an index value beyond the number of available voices, the GetIndVoice function returns a voiceNotFound error.
  8629. SPECIAL CONSIDERATIONS
  8630. Because the GetIndVoice function moves memory, you should not call it at interrupt time.
  8631. ASSEMBLY-LANGUAGE INFORMATION
  8632. The trap macro and routine selector for the GetIndVoice function are
  8633. Trap macro    Selector    
  8634. _SoundDispatch    $030C000C    
  8635.  
  8636. RESULT CODESnoErr    0    No error    
  8637. voiceNotFound    –244    Voice resource not found    
  8638.  
  8639. GetVoiceDescription
  8640.  
  8641. You can obtain a description of a voice by using the GetVoiceDescription function.
  8642. FUNCTION GetVoiceDescription (voice: VoiceSpecPtr; 
  8643.                                             info: VoiceDescriptionPtr;
  8644.                                             infoLength: LongInt): OSErr;
  8645. voice    A pointer to the voice specification record identifying the voice to be described, or NULL to obtain a description of the system default voice.
  8646. info    A pointer to a voice description record. If this parameter is NULL, the function does not fill in the fields of the voice description record; instead, it simply determines whether the voice parameter specifies an available voice and, if not, returns a voiceNotFound error.
  8647. infoLength
  8648. The length, in bytes, of the voice description record. In the current version of the Speech Manager, the voice description record contains 362 bytes. However, you should always use the SizeOf function to determine the length of this record.
  8649. DESCRIPTION
  8650. The GetVoiceDescription function fills out the voice description record pointed to by the info parameter with the correct information for the voice specified by the voice parameter. It fills in the length field of the voice description record with the number of bytes actually copied. This value will always be less than or equal to the value that your application passes in infoLength before calling GetVoiceDescription. This scheme allows applications targeted for the current version of the Speech Manager to work on future versions that might have longer voice description records; it also allows you to write code for future versions of the Speech Manager that will also run on computers that support only the current version.
  8651. If the voice specification record does not identify an available voice, GetVoiceDescription returns a voiceNotFound error.
  8652. SPECIAL CONSIDERATIONS
  8653. Because the GetVoiceDescription function moves memory, you should not call it at interrupt time.
  8654. ASSEMBLY-LANGUAGE INFORMATION
  8655. The trap macro and routine selector for the GetVoiceDescription function are
  8656. Trap macro    Selector    
  8657. _SoundDispatch    $0610000C    
  8658.  
  8659. RESULT CODESnoErr    0    No error    
  8660. paramErr    –50    Parameter error    
  8661. memFullErr    –108    Not enough memory to load voice into memory    
  8662. voiceNotFound    –244    Voice resource not found    
  8663.  
  8664. GetVoiceInfo
  8665.  
  8666. You can use the GetVoiceInfo function to obtain the same information about a voice that the GetVoiceDescription function provides or to determine in which file and resource a voice is stored. This function is intended primarily for use by synthesizers, but an application can call it too.
  8667. FUNCTION GetVoiceInfo (voice: VoiceSpecPtr; selector: OSType; 
  8668.                                 voiceInfo: Ptr): OSErr;
  8669. voice    A pointer to the voice specification record identifying the voice about which your application requires information, or NIL to obtain information on the system default voice.
  8670. selector    A specification of the type of data being requested. For current versions of the Speech Manager, you should set this field either to soVoiceDescription, if you would like to use the GetVoiceInfo function to mimic the GetVoiceDescription function, or to soVoiceFile, if you would like to obtain information about the location of a voice on disk.
  8671. voiceInfo    A pointer to the appropriate data structure. If the selector is soVoiceDescription, then voiceInfo should be a pointer to a voice description record, and the length field of the record should be set to the length of the voice description record. If the selector is soVoiceFile, then voiceInfo should be a pointer to a voice file information record.
  8672. DESCRIPTION
  8673. The GetVoiceInfo function accepts a selector in the selector parameter that determines the type of information you wish to obtain about the voice specified in the voice parameter. The function then fills the fields of the data structure appropriate to the selector you specify in the voiceInfo parameter.
  8674. If the voice specification is invalid, GetVoiceInfo returns a voiceNotFound error. If there is not enough memory to load the voice into memory to obtain information about it, GetVoiceInfo returns the result code memFullErr.
  8675. SPECIAL CONSIDERATIONS
  8676. Because the GetVoiceInfo function might move memory, you should not call it at interrupt time.
  8677. ASSEMBLY-LANGUAGE INFORMATION
  8678. The trap macro and routine selector for the GetVoiceInfo function are
  8679. Trap macro    Selector    
  8680. _SoundDispatch    $0614000C    
  8681.  
  8682. RESULT CODESnoErr    0    No error    
  8683. memFullErr    –108    Not enough memory to load voice into memory    
  8684. voiceNotFound    –244    Voice resource not found    
  8685.  
  8686. Managing Speech Channels
  8687.  
  8688. To take advantage of any but the most rudimentary of the Speech Manager’s capabilities, you need to use speech channels. However, you cannot create a speech channel simply by declaring a variable of type SpeechChannel. Before your application calls any routine that requires a speech channel as a parameter, you must call the NewSpeechChannel function to allow the Speech Manager to allocate memory associated with the speech channel. Later, you can release the memory occupied by a speech channel by calling the DisposeSpeechChannel function. In general, it is a good idea to create a speech channel just before you need it and then dispose of it as soon as you have finished processing speech through it.
  8689. NewSpeechChannel
  8690.  
  8691. You can use the NewSpeechChannel function to create a new speech channel.
  8692. FUNCTION NewSpeechChannel (voice: VoiceSpecPtr; 
  8693.                                         VAR chan: SpeechChannel): OSErr;
  8694. voice    A pointer to the voice specification record corresponding to the voice to be used for the new speech channel. Pass NIL to create a speech channel using the system default voice.
  8695. chan    On exit, a valid speech channel.
  8696. DESCRIPTION
  8697. The NewSpeechChannel function allocates memory for a speech channel record and sets the speech channel variable pointed to by the chan parameter to point to this speech channel record. The Speech Manager automatically locates and opens a connection to the proper synthesizer for the voice specified by the voice parameter.
  8698. There is no predefined limit to the number of speech channels an application can create. However, system constraints on available RAM, processor loading, and number of available sound channels limit the number of speech channels actually possible.
  8699. sWARNING
  8700. Your application should not attempt to manipulate the data pointed to by a variable of type SpeechChannel. The internal format that the Speech Manager uses for speech channel data is not documented and may change in future versions of system software.s
  8701. SPECIAL CONSIDERATIONS
  8702. Because the NewSpeechChannel function allocates memory, you should not call it at interrupt time.
  8703. ASSEMBLY-LANGUAGE INFORMATION
  8704. The trap macro and routine selector for the NewSpeechChannel function are
  8705. Trap macro    Selector    
  8706. _SoundDispatch    $0418000C    
  8707.  
  8708. RESULT CODESnoErr    0    No error    
  8709. memFullErr    –108    Not enough memory to open speech channel    
  8710. synthOpenFailed    –241    Could not open another speech synthesizer channel    
  8711. voiceNotFound    –244    Voice resource not found    
  8712.  
  8713. DisposeSpeechChannel
  8714.  
  8715. You can use the DisposeSpeechChannel function to dispose of an existing speech channel.
  8716. FUNCTION DisposeSpeechChannel (chan: SpeechChannel): OSErr;
  8717. chan    The speech channel to dispose of.
  8718. DESCRIPTION
  8719. The DisposeSpeechChannel function disposes of the speech channel specified in the chan parameter and releases all memory the channel occupies. If the speech channel specified is producing speech, then the DisposeSpeechChannel function immediately stops speech before disposing of the channel. If you have defined a text-done callback procedure or a speech-done callback procedure, the procedure will not be called before the channel is disposed of.
  8720. The Speech Manager releases any speech channels that have not been explicitly disposed of by an application when the application quits. In general, however, your application should dispose of any speech channels it has created whenever it receives a suspend event. This ensures that other applications can take full advantage of Speech Manager and Sound Manager capabilities.
  8721. SPECIAL CONSIDERATIONS
  8722. Because the DisposeSpeechChannel function might purge memory, you should not call it at interrupt time.
  8723. ASSEMBLY-LANGUAGE INFORMATION
  8724. The trap macro and routine selector for the DisposeSpeechChannel function are
  8725. Trap macro    Selector    
  8726. _SoundDispatch    $021C000C    
  8727.  
  8728. RESULT CODESnoErr    0    No error    
  8729. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8730.  
  8731. Obtaining Information About Speech
  8732.  
  8733. Once you have determined with the Gestalt Manager that the Speech Manager is present, you can use the SpeechManagerVersion function to determine what version is available.
  8734. To determine how many speech channels are currently processing speech in your application, you can use the SpeechBusy function. To determine how many are processing speech in your application and other processes, you can use the SpeechBusySystemWide function.
  8735. SpeechManagerVersion
  8736.  
  8737. You can use the SpeechManagerVersion function to determine the current version of the Speech Manager installed in the system.
  8738. FUNCTION SpeechManagerVersion: NumVersion;
  8739. DESCRIPTION
  8740. The SpeechManagerVersion function returns the version of the Speech Manager installed in the system, in the format of the first 4 bytes of a 'vers' resource. You can use this call to determine whether your program can access features of the Speech Manager that are included in some Speech Manager releases but not in earlier ones. Note, however, that because this chapter documents the initial release of the Speech Manager, all features and techniques described in this chapter should be available in all versions of the Speech Manager.
  8741. SPECIAL CONSIDERATIONS
  8742. You can call the SpeechManagerVersion function at interrupt time.
  8743. ASSEMBLY-LANGUAGE INFORMATION
  8744. The trap macro and routine selector for the SpeechManagerVersion function are 
  8745. Trap macro    Selector    
  8746. _SoundDispatch    $0000000C    
  8747.  
  8748. SpeechBusy
  8749.  
  8750. You can use the SpeechBusy function to determine whether any channels of speech are currently synthesizing speech.
  8751. FUNCTION SpeechBusy: Integer;
  8752. DESCRIPTION
  8753. The SpeechBusy function returns the number of speech channels that are currently synthesizing speech in the application. This is useful when you want to ensure that an earlier speech request has been completed before having the system speak again. Note that paused speech channels are counted among those that are synthesizing speech.
  8754. The speech channel that the Speech Manager allocates internally in response to calls to the SpeakString function is counted in the number returned by SpeechBusy. Thus, if you use just SpeakString to initiate speech, SpeechBusy always returns 1 as long as speech is being produced. When SpeechBusy returns 0, all speech has finished.
  8755. SPECIAL CONSIDERATIONS
  8756. You can call the SpeechBusy function at interrupt time.
  8757. ASSEMBLY-LANGUAGE INFORMATION
  8758. The trap macro and routine selector for the SpeechBusy function are
  8759. Trap macro    Selector    
  8760. _SoundDispatch    $003C000C    
  8761.  
  8762. SpeechBusySystemWide
  8763.  
  8764. You can use the SpeechBusySystemWide function to determine if any speech is currently being synthesized in your application or elsewhere on the computer.
  8765. FUNCTION SpeechBusySystemWide: Integer;
  8766. DESCRIPTION
  8767. The SpeechBusySystemWide function returns the total number of speech channels currently synthesizing speech on the computer, whether they were initiated by your application or process’s code or by some other process executing concurrently. Note that paused speech channels are counted among those channels that are synthesizing speech.
  8768. This function is useful when you want to ensure that no speech is currently being produced anywhere on the Macintosh computer before initiating speech. Although the Speech Manager allows different applications to produce speech simultaneously, this can be confusing to the user. As a result, it is often a good idea for your application to check that no other process is producing speech before producing speech itself. If the difference between the values returned by SpeechBusySystemWide and the SpeechBusy function is 0, no other process is producing speech.
  8769. SPECIAL CONSIDERATIONS
  8770. You can call the SpeechBusySystemWide function at interrupt time.
  8771. ASSEMBLY-LANGUAGE INFORMATION
  8772. The trap macro and routine selector for the SpeechBusySystemWide function are
  8773. Trap macro    Selector    
  8774. _SoundDispatch    $0040000C    
  8775.  
  8776. Changing Speech Attributes
  8777.  
  8778. To determine the rate and pitch at which a speech channel is processing text, you can use the GetSpeechRate and GetSpeechPitch functions. The SetSpeechRate and SetSpeechPitch functions allow you to change rate and pitch.
  8779. The most robust of the Speech Manager’s routines are the GetSpeechInfo and SetSpeechInfo functions. These allow you to obtain many types of information about a speech channel and to change many settings of a speech channel. To specify the operation that you wish to perform, you must pass GetSpeechInfo or SetSpeechInfo a selector. A full list of selectors is provided in “Speech Information Selectors” beginning on page 4-39.
  8780. GetSpeechRate
  8781.  
  8782. You use the GetSpeechRate function to obtain a speech channel’s current speech rate.
  8783. FUNCTION GetSpeechRate (chan: SpeechChannel; VAR rate: Fixed)
  8784.                                 : OSErr;
  8785. chan    The speech channel whose rate you wish to determine.
  8786. rate    On exit, the speech channel’s speech rate, expressed as a fixed-point, words-per-minute value.
  8787. DESCRIPTION
  8788. The GetSpeechRate function returns, in the rate parameter, the speech rate of the speech channel specified by the chan parameter.
  8789. SPECIAL CONSIDERATIONS
  8790. You can call the GetSpeechRate function at interrupt time.
  8791. ASSEMBLY-LANGUAGE INFORMATION
  8792. The trap macro and routine selector for the GetSpeechRate function are
  8793. Trap macro    Selector    
  8794. _SoundDispatch    $0448000C    
  8795.  
  8796. RESULT CODESnoErr    0    No error    
  8797. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8798.  
  8799. SetSpeechRate
  8800.  
  8801. You can set the speech rate of a designated speech channel with the SetSpeechRate function.
  8802. FUNCTION SetSpeechRate (chan: SpeechChannel; rate: Fixed): OSErr;
  8803. chan    The speech channel whose rate you wish to set.
  8804. rate    The new speech rate for the speech channel, expressed as a fixed-point, words-per-minute value.
  8805. DESCRIPTION
  8806. The SetSpeechRate function adjusts the speech rate on the speech channel specified by the chan parameter to the rate specified by the rate parameter. As a general rule, typical speaking rates range from around 150 words per minute to around 180 words per minute. It is important to keep in mind, however, that users will differ greatly in their ability to understand synthesized speech at a particular rate based upon their level of experience listening to the voice and their ability to anticipate the types of utterances they will encounter.
  8807. SPECIAL CONSIDERATIONS
  8808. You can call the SetSpeechRate function at interrupt time.
  8809. ASSEMBLY-LANGUAGE INFORMATION
  8810. The trap macro and routine selector for the SetSpeechRate function are
  8811. Trap macro    Selector    
  8812. _SoundDispatch    $0444000C    
  8813.  
  8814. RESULT CODESnoErr    0    No error    
  8815. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8816.  
  8817. GetSpeechPitch
  8818.  
  8819. You can determine a speech channel’s current speech pitch by using the GetSpeechPitch function.
  8820. FUNCTION GetSpeechPitch (chan: SpeechChannel; VAR pitch: Fixed)
  8821.                                     : OSErr;
  8822. chan    The speech channel whose pitch you wish to determine.
  8823. pitch    On exit, the current pitch of the voice in the speech channel, expressed as a fixed-point frequency value. 
  8824. DESCRIPTION
  8825. The GetSpeechPitch function returns, in the pitch parameter, the pitch of the speech channel specified by the chan parameter. Typical voice frequencies range from around 90 hertz for a low-pitched male voice to perhaps 300 hertz for a high-pitched child’s voice. These frequencies correspond to approximate pitch values in the ranges of 30.000 to 40.000 and 55.000 to 65.000, respectively. For information about the mathematical relationship between pitches and frequencies expressed in hertz, see “Speech Attributes” beginning on page 4-6.
  8826. SPECIAL CONSIDERATIONS
  8827. You can call the GetSpeechPitch function at interrupt time.
  8828. ASSEMBLY-LANGUAGE INFORMATION
  8829. The trap macro and routine selector for the GetSpeechPitch function are
  8830. Trap macro    Selector    
  8831. _SoundDispatch    $0450000C    
  8832.  
  8833. RESULT CODESnoErr    0    No error    
  8834. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8835.  
  8836. SetSpeechPitch
  8837.  
  8838. You can use the SetSpeechPitch function to set the speech pitch on a designated speech channel.
  8839. FUNCTION SetSpeechPitch (chan: SpeechChannel; pitch: Fixed)
  8840.                                     : OSErr;
  8841. chan    The speech channel whose pitch you wish to set.
  8842. pitch    The new pitch for the speech channel, expressed as a fixed-point frequency value.
  8843. DESCRIPTION
  8844. The SetSpeechPitch function changes the current speech pitch on the speech channel specified by the chan parameter to the pitch specified by the pitch parameter. Typical voice frequencies range from around 90 hertz for a low-pitched male voice to perhaps 300 hertz for a high-pitched child’s voice. These frequencies correspond to approximate pitch values in the ranges of 30.000 to 40.000 and 55.000 to 65.000, respectively. For information about the mathematical relationship between pitches and frequencies expressed in hertz, see “Speech Attributes” beginning on page 4-6. Although fixed-point values allow you to specify a wide range of pitches, not all synthesizers will support the full range of pitches. If your application specifies a pitch that a synthesizer cannot handle, it may adjust the pitch to fit within an acceptable range.
  8845. SPECIAL CONSIDERATIONS
  8846. You can call the SetSpeechPitch function at interrupt time.
  8847. ASSEMBLY-LANGUAGE INFORMATION
  8848. The trap macro and routine selector for the SetSpeechPitch function are
  8849. Trap macro    Selector    
  8850. _SoundDispatch    $044C000C    
  8851.  
  8852. RESULT CODESnoErr    0    No error    
  8853. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8854.  
  8855. GetSpeechInfo
  8856.  
  8857. You can use the GetSpeechInfo function to obtain information about a designated speech channel.
  8858. FUNCTION GetSpeechInfo (chan: SpeechChannel; selector: OSType;
  8859.                                     speechInfo: Ptr): OSErr;
  8860. chan    The speech channel about which information is being requested.
  8861. selector    A speech information selector that indicates the type of information being requested.
  8862. speechInfo
  8863. A pointer whose meaning depends on the speech information selector specified in the selector parameter.
  8864. DESCRIPTION
  8865. The GetSpeechInfo function returns, in the data structure pointed to by the speechInfo parameter, the type of information requested by the selector parameter as it applies to the speech channel specified in the chan parameter.
  8866. The format of the data structure specified by the speechInfo parameter depends on the selector you choose. For example, a selector might require that your application allocate a block of memory of a certain size and pass a pointer to that block. Another selector might require that speechInfo be set to the address of a handle variable. In this case, the GetSpeechInfo function would allocate a relocatable block of memory and change the handle variable specified to reference the block.
  8867. SPECIAL CONSIDERATIONS
  8868. You can call the GetSpeechInfo function at interrupt time only if the speech information selector specified in the selector parameter does not move or purge memory.
  8869. ASSEMBLY-LANGUAGE INFORMATION
  8870. The trap macro and routine selector for the GetSpeechInfo function are
  8871. Trap macro    Selector    
  8872. _SoundDispatch    $0658000C    
  8873.  
  8874. RESULT CODESnoErr    0    No error    
  8875. siUnknownInfoType    –231    Feature is not implemented on synthesizer    
  8876. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8877.  
  8878. SEE ALSO
  8879. For a complete list of speech information selectors, see “Speech Information Selectors” beginning on page 4-39. This list indicates how your application should set the speechInfo parameter for each selector and indicates which selectors might cause memory to be moved or purged.
  8880. SetSpeechInfo
  8881.  
  8882. You can use the SetSpeechInfo function to change a setting of a particular speech channel.
  8883. FUNCTION SetSpeechInfo (chan: SpeechChannel; selector: OSType;
  8884.                                 speechInfo: Ptr): OSErr;
  8885. chan    The speech channel for which your application wishes to change a setting.
  8886. selector    A speech information selector that indicates the type of information being changed.
  8887. speechInfo
  8888. A pointer whose meaning depends on the speech information selector specified in the selector parameter.
  8889. DESCRIPTION
  8890. The SetSpeechInfo function changes the type of setting indicated by the selector parameter in the speech channel specified by the chan parameter, based on the data your application provides via the speechInfo parameter.
  8891. The format of the data structure specified by the speechInfo parameter depends on the selector you choose. Ordinarily, a selector requires that speechInfo be a pointer to a data structure that specifies a new setting for the speech channel.
  8892. SPECIAL CONSIDERATIONS
  8893. You can call the SetSpeechInfo function at interrupt time only if the speech information selector specified in the selector parameter does not move or purge memory.
  8894. ASSEMBLY-LANGUAGE INFORMATION
  8895. The trap macro and routine selector for the SetSpeechInfo function are
  8896. Trap macro    Selector    
  8897. _SoundDispatch    $0654000C    
  8898.  
  8899. RESULT CODESnoErr    0    No error    
  8900. paramErr    –50    Parameter value is invalid    
  8901. siUnknownInfoType    –231    Feature is not implemented on synthesizer    
  8902. incompatibleVoice    –245    Specified voice cannot be used with synthesizer    
  8903. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8904.  
  8905. SEE ALSO
  8906. For a complete list of speech information selectors, see “Speech Information Selectors” beginning on page 4-39. This list indicates how your application should set the speechInfo parameter for each selector and indicates which selectors might cause memory to be moved or purged.
  8907. Converting Text To Phonemes
  8908.  
  8909. The Speech Manager provides a utility routine, the TextToPhonemes function, to convert textual data into phonetic data. This is particularly useful during application development, when you might wish to adjust phrases that your application generates to produce smoother speech. By first converting the target phrase into phonemes, you can see what the synthesizer will try to speak. Then you need correct only the parts that would not have been spoken the way you want.
  8910. TextToPhonemes
  8911.  
  8912. You can use the TextToPhonemes function to convert textual data into phonemic data.
  8913. FUNCTION TextToPhonemes (chan: SpeechChannel; textBuf: Ptr;
  8914.                                     textBytes: LongInt; phonemeBuf: Handle;
  8915.                                     VAR phonemeBytes: LongInt): OSErr;
  8916. chan    A speech channel whose associated synthesizer and voice are to be used for the conversion process.
  8917. textBuf    A pointer to a buffer of text to be converted.
  8918. textBytes    The number of bytes of text to be converted.
  8919. phonemeBuf
  8920. A handle to a buffer to be used to store the phonemic data. The TextToPhonemes function may resize the relocatable block referenced by this handle.
  8921. phonemeBytes
  8922. On exit, the number of bytes of phonemic data written to the handle.
  8923. DESCRIPTION
  8924. The TextToPhonemes function converts the textBytes bytes of textual data pointed to by the textBuf parameter to phonemic data, which it writes into the relocatable block specified by the phonemeBuf parameter. If necessary, TextToPhonemes resizes this relocatable block. The TextToPhonemes function sets the phonemeBytes parameter to the number of bytes of phonetic data actually written.
  8925. sWARNING
  8926. If the textual data is contained in a relocatable block, a handle to that block must be locked before the TextToPhonemes function is called. s
  8927. The data returned by TextToPhonemes corresponds precisely to the phonemes that would be spoken had the input text been sent to SpeakText instead. All current mode settings for the speech channel specified by chan are applied to the converted speech. No callbacks are generated while the TextToPhonemes routine is generating its output.
  8928. SPECIAL CONSIDERATIONS
  8929. Because the TextToPhonemes function might move memory, you should not call it at interrupt time.
  8930. ASSEMBLY-LANGUAGE INFORMATION
  8931. The trap macro and routine selector for the TextToPhonemes function are
  8932. Trap macro    Selector    
  8933. _SoundDispatch    $0A5C000C    
  8934.  
  8935. RESULT CODESnoErr    0    No error    
  8936. paramErr    –50    Parameter value is invalid    
  8937. nilHandleErr    –109    Handle argument is NIL    
  8938. siUnknownInfoType    –231    Feature not implemented on synthesizer    
  8939. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8940.  
  8941. Installing a Pronunciation Dictionary
  8942.  
  8943. Pronunciation dictionaries allow your application to override the default Speech Manager pronunciations of individual words, such as names with quirky spellings. The UseDictionary function allows your application to load a pronunciation dictionary into a speech channel.
  8944. UseDictionary
  8945.  
  8946. You can use the UseDictionary function to install a designated dictionary into a speech channel.
  8947. FUNCTION UseDictionary (chan: SpeechChannel; dictionary: Handle)
  8948.                                 : OSErr;
  8949. chan    The speech channel into which a dictionary is to be installed.
  8950. dictionary
  8951. A handle to the dictionary data. This is often a handle to a resource of type 'dict'.
  8952. DESCRIPTION
  8953. The UseDictionary function attempts to install the dictionary data referenced by the dictionary parameter into the speech channel referenced by the chan parameter. The synthesizer will use whatever elements of the dictionary resource it considers useful to the speech conversion process. Some speech synthesizers might ignore certain types of dictionary entries.
  8954. After the UseDictionary function returns, your application is free to release any storage allocated for the dictionary handle. The search order for application-provided dictionaries is last-in, first-searched.
  8955. All details of how an application-provided dictionary is represented within the speech synthesizer are dependent on the specific synthesizer implementation and are private to the synthesizer.
  8956. SPECIAL CONSIDERATIONS
  8957. Because the UseDictionary function might move memory, you should not call it at interrupt time.
  8958. ASSEMBLY-LANGUAGE INFORMATION
  8959. The trap macro and routine selector for the UseDictionary function are
  8960. Trap macro    Selector    
  8961. _SoundDispatch    $0460000C    
  8962.  
  8963. RESULT CODESnoErr    0    No error    
  8964. memFullErr    –108    Not enough memory to use new dictionary    
  8965. badDictFormat    –246    Pronunciation dictionary format error    
  8966. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  8967.  
  8968. SEE ALSO
  8969. For a description of the format of a pronunciation dictionary, see “The Pronunciation Dictionary Resource” on page 4-89. For a discussion of how you might manipulate a dictionary in memory, see “Including Pronunciation Dictionaries” beginning on page 4-36.
  8970. Application-Defined Routines
  8971.  
  8972. The Speech Manager allows you to define callback procedures that execute
  8973. n    when text input processing is complete (but not necessarily after speech has stopped)
  8974. n    when text has been completely processed and spoken
  8975. n    whenever the Speech Manager encounters an embedded synchronization command
  8976. n    whenever the Speech Manager encounters an error in processing embedded speech commands
  8977. n    whenever a phoneme is about to be spoken
  8978. n    whenever a word is about to be spoken
  8979. sWARNING
  8980. When the Speech Manager executes a callback procedure, the Speech Manager sets the A5 register to the value specified by the most recent call to the SetSpeechInfo function with the soCurrentA5 selector. However, if the most recent value specified with the soCurrentA5 selector is NIL or if your application has not yet specified a value, then the Speech Manager leaves the A5 register unchanged. In this case, the callback procedure cannot access application global variables because it executes at interrupt time. For code showing how to use the soCurrentA5 selector to ensure that the A5 register is set to your application’s A5, see Listing 4-6 on page 4-21.s
  8981. Text-Done Callback Procedure
  8982.  
  8983. You can specify a text-done callback procedure by passing the soTextDoneCallBack selector to the SetSpeechInfo function.
  8984. MyTextDoneCallback
  8985.  
  8986. A text-done callback procedure has the following syntax:
  8987. PROCEDURE MyTextDoneCallback 
  8988.                                     (chan: SpeechChannel; refCon: LongInt; 
  8989.                                     VAR nextBuf: Ptr; VAR byteLen: LongInt; 
  8990.                                     VAR controlFlags: LongInt);
  8991. chan    The speech channel that has finished processing input text.
  8992. refCon    The reference constant associated with the speech channel.
  8993. nextBuf    On exit, a pointer to the next buffer of text to process or NIL if your application has no additional text to be spoken. This parameter is mostly for internal use by the Speech Manager.
  8994. byteLen    On exit, the number of bytes of the text buffer pointed to by the nextBuf parameter.
  8995. controlFlags
  8996. On exit, the control flags to be used in generating the next buffer of text.
  8997.  DESCRIPTION
  8998. If a text-done callback procedure is installed in a speech channel, then the Speech Manager calls this procedure when it finishes processing a buffer of text. The Speech Manager might not yet have completed finishing speaking the text and indeed might not have started speaking it.
  8999. A common use of a text-done callback procedure is to alert your application once the text passed to the SpeakText or SpeakBuffer function can be disposed of (or, when the text is contained within a locked relocatable block, when the relocatable block can be unlocked). The Speech Manager copies the text you pass to the SpeakText or SpeakBuffer function into an internal buffer. Once it has finished processing the text, you may dispose of the original text buffer, even if speech is not yet complete. However, if you wish to write a callback procedure that executes when speech is completed, see the definition of a speech-done callback procedure below.
  9000. Although most applications won’t need to, your callback procedure can indicate to the Speech Manager whether there is another buffer of text to speak. If there is another buffer, your callback procedure should reference it by setting the nextBuf and byteLen parameters to appropriate values. (Your callback procedure might also change the control flags to be used to process the speech by altering the value in the controlFlags parameter.) Setting these parameters allows the Speech Manager to generate uninterrupted speech. If there is no more text to speak, your callback procedure should set nextBuf to NIL. In this case, the Speech Manager ignores the byteLen and controlFlags parameters.
  9001. If your text-done callback procedure does not change the values of the nextBuf and byteLen parameters, the text buffer just spoken will be spoken again.
  9002. SPECIAL CONSIDERATIONS
  9003. Because your callback procedure executes at interrupt time, you must not call any routines that might move or purge memory. If you are writing a callback procedure so that your application will know when it can dispose of a text buffer, then use the callback procedure to set a global flag variable. Your application’s main event loop can check this flag and dispose of the text buffer if it is set.
  9004. Your callback procedure is able to access application global variables only if the A5 register is properly set. The Speech Manager sets A5 to the proper value if you provide your application’s A5 value by calling the SetSpeechInfo function with the soCurrentA5 selector.
  9005. ASSEMBLY-LANGUAGE INFORMATION
  9006. Because a callback procedure is called at interrupt time, it must preserve all registers other than A0–A2 and D0–D2.
  9007. Speech-Done Callback Procedure
  9008.  
  9009. You can specify a speech-done callback procedure by passing the soSpeechDoneCallBack selector to the SetSpeechInfo function.
  9010. MySpeechDoneCallback
  9011.  
  9012. A speech-done callback procedure has the following syntax:
  9013. PROCEDURE MySpeechDoneCallback (chan: SpeechChannel; 
  9014.                                             refCon: LongInt);
  9015. chan    The speech channel that has finished processing input text.
  9016. refCon    The reference constant associated with the speech channel.
  9017. DESCRIPTION
  9018. If a speech-done callback procedure is installed in a speech channel, then the Speech Manager calls this procedure when it finishes speaking a buffer of text.
  9019. You might use a speech-done callback procedure if you need to update some visual indicator that shows what text is currently being spoken. For example, suppose your application passes text buffers to the Speech Manager one paragraph at a time. Your speech-done callback procedure might set a global flag variable to indicate to the application that the Speech Manager has finished speaking a paragraph. When a routine called by your application’s main event loop checks the global flag variable and determines that it has been set, the routine might ensure that the next paragraph of text is visible.
  9020. You might use a speech-done callback procedure to set a flag variable that alerts the application that it should pass a new buffer of text to the Speech Manager. If you do so, however, there might be a noticeable pause as the Speech Manager switches from processing one text buffer to another. Ordinarily, it is easier to achieve this goal by using a text-done callback procedure, as described earlier.
  9021. SPECIAL CONSIDERATIONS
  9022. Because your callback procedure executes at interrupt time, you must not call any routines that might move or purge memory.
  9023. Your callback procedure is able to access application global variables only if the A5 register is properly set. The Speech Manager sets A5 to the proper value if you provide your application’s A5 value by calling the SetSpeechInfo function with the soCurrentA5 selector.
  9024. ASSEMBLY-LANGUAGE INFORMATION
  9025. Because a callback procedure is called at interrupt time, it must preserve all registers other than A0–A2 and D0–D2.
  9026. Synchronization Callback Procedure
  9027.  
  9028. You can specify a synchronization callback procedure by passing the soSyncCallBack selector to the SetSpeechInfo function and embedding a synchronization command within a text buffer passed to the SpeakText or SpeakBuffer function.
  9029. MySynchronizationCallback
  9030.  
  9031. A synchronization callback procedure has the following syntax:
  9032. PROCEDURE MySynchronizationCallback (chan: SpeechChannel; 
  9033.                                                     refCon: LongInt;
  9034.                                                     syncMessage: OSType);
  9035. chan    The speech channel that has finished processing input text.
  9036. refCon    The reference constant associated with the speech channel.
  9037. syncMessage
  9038. The synchronization message passed in the embedded command. Usually, you use this message to distinguish between several different types of synchronization commands, but you can use it any way you wish.
  9039. DESCRIPTION
  9040. The Speech Manager calls a speech channel’s synchronization callback procedure whenever it encounters a synchronization command embedded in a text buffer. You might use the synchronization callback procedure to provide a callback not ordinarily provided. For example, you might inset synchronization commands at the end of every sentence in a text buffer, or you might enter synchronization commands after every numeric value in the text. However, to synchronize your application with phonemes or words, it makes more sense to use the built-in phoneme and word callback procedures, defined in “Phoneme Callback Procedure” on page 4-87 and “Word Callback Procedure” on page 4-88.
  9041. SPECIAL CONSIDERATIONS
  9042. Because your callback procedure executes at interrupt time, you must not call any routines that might move or purge memory. If you need to make a visual change in response to a synchronization command, then use the callback procedure to set a global flag variable. Your application’s main event loop can check this flag and update the screen display if it is set.
  9043. Your callback procedure is able to access application global variables only if the A5 register is properly set. The Speech Manager sets A5 to the proper value if you provide your application’s A5 value by calling the SetSpeechInfo function with the soCurrentA5 selector.
  9044. ASSEMBLY-LANGUAGE INFORMATION
  9045. Because a callback procedure is called at interrupt time, it must preserve all registers other than A0–A2 and D0–D2.
  9046. Error Callback Procedure
  9047.  
  9048. You can specify an error callback procedure by passing the soErrorCallBack selector to the SetSpeechInfo function.
  9049. MyErrorCallback
  9050.  
  9051. An error callback procedure has the following syntax:
  9052. PROCEDURE MyErrorCallback (chan: SpeechChannel; refCon: LongInt;
  9053.                                     error: OSErr; bytePos: LongInt);
  9054. chan    The speech channel that has finished processing input text.
  9055. refCon    The reference constant associated with the speech channel.
  9056. error    The error that occurred in processing an embedded command.
  9057. bytePos    The number of bytes from the beginning of the text buffer being spoken to the error encountered.
  9058. DESCRIPTION
  9059. The Speech Manager calls a speech channel’s error callback procedure whenever it encounters a syntax error within a command embedded in a text buffer it is processing. This can be useful during application debugging, to detect problems with commands that you have embedded in text buffers that your application speaks. It can also be useful if your application allows users to embed commands within text buffers. Your application might display an alert indicating that the Speech Manager encountered a problem in processing an embedded command.
  9060. Ordinarily, the error information that the Speech Manager provides the error callback procedure should be sufficient. However, if your application needs information about errors that occurred before the error callback procedure was enabled, the application (including the error callback procedure) can call the GetSpeechInfo function with the soErrors selector.
  9061. SPECIAL CONSIDERATIONS
  9062. Because your callback procedure executes at interrupt time, you must not call any routines that might move or purge memory. If you need to display an alert box to the user, then use the callback procedure to set a global flag variable. Your application’s main event loop can check this flag and display the alert box if it is set.
  9063. Your callback procedure is able to access application global variables only if the A5 register is properly set. The Speech Manager sets A5 to the proper value if you provide your application’s A5 value by calling the SetSpeechInfo function with the soCurrentA5 selector.
  9064. ASSEMBLY-LANGUAGE INFORMATION
  9065. Because a callback procedure is called at interrupt time, it must preserve all registers other than A0–A2 and D0–D2.
  9066. Phoneme Callback Procedure
  9067.  
  9068. You can specify a phoneme callback procedure by passing the soPhonemeCallBack selector to the SetSpeechInfo function.
  9069. MyPhonemeCallback
  9070.  
  9071. A phoneme callback procedure has the following syntax:
  9072. PROCEDURE MyPhonemeCallback (chan: SpeechChannel; refCon: LongInt;
  9073.                                         phonemeOpcode: Integer);
  9074. chan    The speech channel that has finished processing input text.
  9075. refCon    The reference constant associated with the speech channel.
  9076. phonemeOpcode
  9077. The phoneme about to be pronounced.
  9078. DESCRIPTION
  9079. The Speech Manager calls a speech channel’s phoneme callback procedure just before it pronounces a phoneme. For example, your application might use such a callback procedure to enable mouth synchronization. In this case, the callback procedure would set a global flag variable to indicate that the phoneme being pronounced is changing and another global variable to phonemeOpcode. A routine called by your application’s main event loop could detect that the phoneme being pronounced is changing and update a picture of a mouth to reflect the current phoneme. In practice, providing a visual indication of the pronunciation of a phoneme requires several consecutive pictures of mouth movement to be rapidly displayed. Consult the linguistics literature for information on mouth movements associated with different phonemes.
  9080. SPECIAL CONSIDERATIONS
  9081. Because your callback procedure executes at interrupt time, you must not call any routines that might move or purge memory.
  9082. Your callback procedure is able to access application global variables only if the A5 register is properly set. The Speech Manager sets A5 to the proper value if you provide your application’s A5 value by calling the SetSpeechInfo function with the soCurrentA5 selector.
  9083. ASSEMBLY-LANGUAGE INFORMATION
  9084. Because a callback procedure is called at interrupt time, it must preserve all registers other than A0–A2 and D0–D2.
  9085. Word Callback Procedure
  9086.  
  9087. You can specify a word callback procedure by passing the soWordCallBack selector to the SetSpeechInfo function.
  9088. MyWordCallback
  9089.  
  9090. A word callback procedure has the following syntax:
  9091. PROCEDURE MyWordCallback (chan: SpeechChannel; refCon: LongInt;
  9092.                                     wordPos: LongInt; wordLen: Integer);
  9093. chan    The speech channel that has finished processing input text.
  9094. refCon    The reference constant associated with the speech channel.
  9095. wordPos    The number of bytes between the beginning of the text buffer and the beginning of the word about to be pronounced.
  9096. wordLen    The length in bytes of the word about to be pronounced.
  9097. DESCRIPTION
  9098. The Speech Manager calls a speech channel’s word callback procedure just before it pronounces a word. You might use such a callback procedure, for example, to draw the word about to be spoken in a window. In this case, the callback procedure would set a global flag variable to indicate that the word being spoken is changing and another two global variables to wordPos and wordLen. A routine called by your application’s main event loop could detect that the word being spoken is changing and draw the word in a window.
  9099. SPECIAL CONSIDERATIONS
  9100. Because your callback procedure executes at interrupt time, you must not call any routines that might move or purge memory.
  9101. Your callback procedure is able to access application global variables only if the A5 register is properly set. The Speech Manager sets A5 to the proper value if you provide your application’s A5 value by calling the SetSpeechInfo function with the soCurrentA5 selector.
  9102. ASSEMBLY-LANGUAGE INFORMATION
  9103. Because a callback procedure is called at interrupt time, it must preserve all registers other than A0–A2 and D0–D2.
  9104. Resources
  9105.  
  9106. This section describes the format of a pronunciation dictionary resource, which the Speech Manager uses to override its default pronunciation of words. The Speech Manager uses pronunciation rules as well as an internal dictionary (not stored in the same format as pronunciation dictionary resources) to determine how to pronounce words not included in a speech channel’s installed pronunciation dictionaries. For an introduction to the use of and examples showing how your application can install and manipulate pronunciation dictionaries, see “Including Pronunciation Dictionaries” beginning on page 4-36.
  9107. This section does not describe the format of voice resources or speech synthesizer resources, because you should not need to access them directly.
  9108. The Pronunciation Dictionary Resource
  9109.  
  9110. You can store a list of words and their associated pronunciations in a resource of resource type 'dict'. You can associate any number of dictionary resources with a speech channel. Before using its internal rules to pronounce a word, the Speech Manager searches the dictionary resources that your application has associated with the speech channel in a last-in, first-searched order.
  9111. Note
  9112. Note
  9113. Because your application is responsible for loading data from a pronunciation dictionary into memory, you can, if desired, store pronunciation information in the data fork of a file rather than in the resource fork. Also, you can devise your own format in which to store pronunciation data, as long as you convert that data into the format described in this section before calling the UseDictionary function.u
  9114. Figure 4-5 shows the format of a pronunciation dictionary resource.
  9115. Figure 4-5    Format of a pronunciation dictionary resource
  9116.  
  9117. Note
  9118. Note
  9119. Some synthesizers might use resources (such as resources of type 'ttsd') to store their internal pronunciation dictionaries. These internal dictionaries are not necessarily in the same format as the pronunciation dictionaries described here.u
  9120. To define a dictionary resource, you ordinarily use a resource of type 'dict'. Such a resource contains a pronunciation dictionary resource header, which is at the start of the resource and defines characteristics of the dictionary as a whole, and any number of pronunciation dictionary entries. Each pronunciation dictionary entry corresponds to one word and contains one or more pronunciation dictionary entry fields. Each pronunciation dictionary entry field contains one piece of information about the word being described in the entry; for example, a dictionary entry would include a field with a textual representation of the word.
  9121. The pronunciation dictionary resource header includes the following:
  9122. n    Total byte length. The total number of bytes of the dictionary, including the entire pronunciation dictionary resource header in addition to the dictionary’s entries.
  9123. n    Atom type. The currently defined atom type is 'dict'. Future versions of the Speech Manager might define additional atom types for other types of dictionaries.
  9124. n    Format version. The currently defined format version is 1. Future versions of the Speech Manager might support additional format versions for the 'dict' atom type.
  9125. n    Script code. The script code of words defined in the pronunciation dictionary (for example, smRoman). All words in a dictionary must be in the same script.
  9126. n    Language code. The language code of words defined in the pronunciation dictionary (for example, langEnglish). All words in a dictionary must be in the same language.
  9127. n    Region code. The region code of pronunciations in the dictionary (for example, verUS). All words in a dictionary must target the same region.
  9128. n    Date last modified. The number of seconds between midnight, January 1, 1904, and the modification time. You can use the GetDateTime procedure to determine the number of seconds between midnight, January 1, 1904, and the current time. For more information, see Inside Macintosh: Operating System Utilities.
  9129. n    Reserved. These 16 bytes are reserved for future use. You should set them to 0.
  9130. n    Entry count. The number of dictionary entries.
  9131. Immediately following the pronunciation dictionary resource header is a list of the pronunciation dictionary entries.
  9132. Figure 4-6 shows the format of a pronunciation dictionary entry.
  9133. Figure 4-6    Format of a dictionary entry in a dictionary resource
  9134.  
  9135. Each pronunciation dictionary entry consists of the following:
  9136. n    Entry byte length. The total number of bytes in the entry, including this word.
  9137. n    Entry type. A code for the type of pronunciation dictionary entry. The code $0000 represents a null entry, and codes $0001 through $0020 are reserved for future use by Apple Computer, Inc. You should thus ordinarily fill in this field with $0021, which is the code for a pronunciation entry, or $0022, which is the code for an abbreviation entry. In the current version of the Speech Manager, abbreviation entries work just like pronunciation entries.
  9138. n    Field count. The number of pronunciation dictionary entry fields contained within this entry.
  9139. Immediately following the field count indicator are the fields themselves. Typically, a pronunciation entry always includes a field containing the word in textual format and a field containing the phonetic pronunciation of the word.
  9140. Each field within a dictionary entry has the format illustrated in Figure 4-7.
  9141. Figure 4-7    Format of a dictionary entry field
  9142.  
  9143. The three parts of a dictionary entry field are as follows:
  9144. n    Field byte length. The total number of bytes in the pronunciation entry field, not including the pad byte of the field data when applicable.
  9145. n    Field type. A code for the format of the pronunciation dictionary entry field’s data. The code $0000 represents a null entry field, and Apple reserves codes $0001 through $0020 as well as code $0023 for future use. Code $0021 represents a textual representation of the word being described in the entry. Code $0022 represents a phonetic pronunciation of the word, including a complete set of syllable, lexical stress, word prominence, and prosodic marks, all represented in textual format.
  9146. n    Field data. If the field type is $0021 or $0022, then this field contains characters representing the word textually or phonetically, respectively. The characters are not preceded by a length byte and are not followed by a null character. However, if there are an odd number of characters, then a byte must be added as padding to ensure that fields align on word boundaries. The pad byte need not be set to a particular value.
  9147.  
  9148.  
  9149. Summary of the Speech Manager
  9150.  
  9151. Pascal Summary
  9152.  
  9153. Constants
  9154.  
  9155. CONST
  9156.     {Gestalt selector and response bits for speech attributes}
  9157.     gestaltSpeechAttr                                    = 'ttsc';                {speech attributes selector}
  9158.     gestaltSpeechMgrPresent                                    = 0;                {Speech Manager is present}
  9159.     gestaltSpeechHasPPCGlue                                    = 1;                {native glue for PowerPC present}
  9160.     {Operating System types}
  9161.     kTextToSpeechSynthType                                    = 'ttsc';                {synthesizer component type}
  9162.     kTextToSpeechVoiceType                                    = 'ttvd';                {voice resource type}
  9163.     kTextToSpeechVoiceFileType                                    = 'ttvf';                {voice file type}
  9164.     kTextToSpeechVoiceBundleType
  9165.                                         = 'ttvb';                {voice bundle file type}
  9166.     {masks for SpeakBuffer and text-done callback control flags}
  9167.     kNoEndingProsody                                = 1;                {disable prosody at end of sentences}
  9168.     kNoSpeechInterrupt                                = 2;                {do not interrupt current speech}
  9169.     kPreflightThenPause                                = 4;                {compute speech without generating}
  9170.     {constants for StopSpeechAt and PauseSpeechAt}
  9171.     kImmediate                                = 0;                {stop immediately}
  9172.     kEndOfWord                                = 1;                {stop at end of word}
  9173.     kEndOfSentence                                = 2;                {stop at end of sentence}
  9174.     {GetSpeechInfo and SetSpeechInfo selectors}
  9175.     soCharacterMode                                = 'char';                {get or set character-processing mode}
  9176.     soCommandDelimiter                                = 'dlim';                {set embedded command delimiters}
  9177.     soCurrentA5                                = 'myA5';                {set A5 on callbacks}
  9178.     soCurrentVoice                                = 'cvox';                {set speaking voice}
  9179.     soErrorCallBack                                = 'ercb';                {set error callback}
  9180.     soErrors                                = 'erro';                {get error information}
  9181.     soInputMode                                = 'inpt';                {get or set text-processing mode}
  9182.     soNumberMode                                = 'nmbr';                {get or set number-processing mode}
  9183.     soPhonemeCallBack                                = 'phcb';                {set phoneme callback}
  9184.     soPhonemeSymbols                                = 'phsy';                {get phoneme symbols and sample words}
  9185.     soPitchBase                                = 'pbas';                {get or set baseline pitch}
  9186.     soPitchMod                                = 'pmod';                {get or set pitch modulation}
  9187.     soRate                                = 'rate';                {get or set speech rate}
  9188.     soRecentSync                                = 'sync';                {get most recent synchronization }
  9189.                                                     { message information}
  9190.     soRefCon                                = 'refc';                {set reference constant value}
  9191.     soReset                                = 'rset';                {set channel back to default state}
  9192.     soSpeechDoneCallBack                                = 'sdcb';                {set speech-done callback}
  9193.     soStatus                                = 'stat';                {get status of channel}
  9194.     soSyncCallBack                                = 'sycb';                {set synchronization callback}
  9195.     soSynthExtension                                = 'xtnd';                {get or set synthesizer-specific }
  9196.                                                     { information}
  9197.     soSynthType                                = 'vers';                {get synthesizer information}
  9198.     soTextDoneCallBack                                = 'tdcb';                {set text-done callback}
  9199.     soVolume                                = 'volm';                {get or set speech volume}
  9200.     soWordCallBack                                = 'wdcb';                {set word callback}
  9201.     {input mode constants}
  9202.     modeText                            = 'TEXT';
  9203.     modePhonemes                            = 'PHON';
  9204.     {character and number mode constants}
  9205.     modeNormal                            = 'NORM';
  9206.     modeLiteral                            = 'LTRL';
  9207.     {GetVoiceInfo selectors}
  9208.     soVoiceDescription                            = 'info';                    {get basic voice information}
  9209.     soVoiceFile                            = 'fref';                    {get voice file reference information}
  9210.     {genders}
  9211.     kNeuter                            = 0;
  9212.     kMale                            = 1;
  9213.     kFemale                            = 2;
  9214. Data Structures
  9215.  
  9216. Speech Channel Record
  9217. TYPE
  9218.     SpeechChannelRecord                             = LongInt;                                    {speech channel record}
  9219.     SpeechChannel                            = ^SpeechChannelRecord;                                    {speech channel}
  9220.     SpeechChannelPtr                            = ^SpeechChannel;                                    {speech channel pointer}
  9221. Voice Specification Record
  9222.     VoiceSpec =
  9223.     RECORD
  9224.         creator:                        OSType;                    {ID of required synthesizer}
  9225.         id:                        OSType;                    {ID of voice on the synthesizer}
  9226.     END;
  9227.     VoiceSpecPtr = ^VoiceSpec;
  9228. Voice Description Record
  9229.     VoiceDescription =
  9230.     RECORD
  9231.         length:                        LongInt;                    {size of record--set by application}
  9232.         voice:                        VoiceSpec;                    {voice synthesizer and ID info}
  9233.         version:                        LongInt;                    {version number of voice}
  9234.         name:                        Str63;                    {name of voice}
  9235.         comment:                        Str255;                    {text information about voice}
  9236.         gender:                        Integer;                    {neuter, male, or female}
  9237.         age:                        Integer;                    {approximate age in years}
  9238.         script:                        Integer;                    {script code of text voice can }
  9239.                                                     { process}
  9240.         language:                        Integer;                    {language code of voice output}
  9241.         region:                        Integer;                    {region code of voice output}
  9242.         reserved1:                        LongInt;                    {always 0--reserved for future use}
  9243.         reserved2:                        LongInt;                    {always 0--reserved for future use}
  9244.         reserved3:                        LongInt;                    {always 0--reserved for future use}
  9245.         reserved4:                        LongInt;                    {always 0--reserved for future use}
  9246.     END;
  9247.     VoiceDescriptionPtr = ^VoiceDescription;
  9248. Voice File Information Record
  9249.     VoiceFileInfo =
  9250.     RECORD
  9251.         fileSpec:                        FSSpec;                    {volume, dir, and name of file}
  9252.         resID:                        Integer;                    {resource ID of voice in the file}
  9253.     END;
  9254.     VoiceFileInfoPtr = ^VoiceFileInfo;
  9255. Speech-Status Information Record
  9256.     SpeechStatusInfo =
  9257.     RECORD
  9258.         outputBusy:                        Boolean;                    {TRUE if audio is playing}
  9259.         outputPaused:                        Boolean;                    {TRUE if channel is paused}
  9260.         inputBytesLeft:                        LongInt;                    {bytes of text left to process}
  9261.         phonemeCode:                        Integer;                    {opcode for current phoneme}
  9262.     END;
  9263.     SpeechStatusInfoPtr = ^SpeechStatusInfo;
  9264. Speech Error Information Record
  9265.     SpeechErrorInfo =
  9266.     RECORD
  9267.         count:                        Integer;                     {number of errors since last check}
  9268.         oldest:                        OSErr;                    {oldest unread error}
  9269.         oldPos:                        LongInt;                    {character position of oldest error}
  9270.         newest:                        OSErr;                    {most recent error}
  9271.         newPos:                        LongInt;                    {character position of newest error}
  9272.     END;
  9273. Speech Version Information Record
  9274.     SpeechVersionInfo =
  9275.     RECORD
  9276.         synthType:                        OSType;                    {general synthesizer type}
  9277.         synthSubType:                        OSType;                    {specific synthesizer type}
  9278.         synthManufacturer:
  9279.                                 OSType;                    {synthesizer creator ID}
  9280.         synthFlags:                        LongInt;                    {synthesizer feature flags}
  9281.         synthVersion:                        NumVersion;                    {synthesizer version number}
  9282.     END;
  9283.     SpeechVersionInfoPtr = ^SpeechVersionInfo;
  9284. Phoneme Information Record
  9285.     PhonemeInfo =
  9286.     RECORD
  9287.         opCode:                        Integer;                    {opcode for the phoneme}
  9288.         phStr:                        Str15;                    {corresponding character string}
  9289.         exampleStr:                        Str31;                    {word that shows use of phoneme}
  9290.         hiliteStart:                        Integer;                    {offset from beginning of word }
  9291.                                                     { to beginning of phoneme sound}
  9292.         hiliteEnd:                        Integer;                    {offset from beginning of word }
  9293.                                                     { to end of phoneme sound}
  9294.     END;
  9295. Phoneme Descriptor Record
  9296.     PhonemeDescriptor =
  9297.     RECORD
  9298.         phonemeCount:                        Integer;                     {number of phonemes defined by }
  9299.                                                     { current synthesizer}
  9300.                                                     {list of phoneme information records}
  9301.         thePhonemes:                        ARRAY[0..0] OF PhonemeInfo;
  9302.     END;
  9303. Speech Extension Data Record
  9304.     SpeechXtndData =
  9305.     RECORD
  9306.         synthCreator:                        OSType;                    {synthesizer creator ID}
  9307.                                                     {data used by synthesizer}
  9308.         synthData:                        PACKED ARRAY[0..1] OF Char;
  9309.     END;
  9310. Delimiter Information Record
  9311.     DelimiterInfo =
  9312.     RECORD
  9313.         startDelimiter:                        PACKED ARRAY[0..1] OF Char;                                        {start delimiter}
  9314.         endDelimiter:                        PACKED ARRAY[0..1] OF Char;                                        {end delimiter}
  9315.     END;
  9316. Speech Manager Routines
  9317.  
  9318. Starting, Stopping, and Pausing Speech
  9319. FUNCTION SpeakString    (s: Str255): OSErr;
  9320. FUNCTION SpeakText    (chan: SpeechChannel; textBuf: Ptr; byteLen:LongInt): OSErr;
  9321. FUNCTION SpeakBuffer    (chan: SpeechChannel; textBuf: Ptr; byteLen:LongInt; controlFlags: LongInt): OSErr;
  9322. FUNCTION StopSpeech    (chan: SpeechChannel): OSErr;
  9323. FUNCTION StopSpeechAt    (chan: SpeechChannel; whereToStop: LongInt): OSErr;
  9324. FUNCTION PauseSpeechAt    (chan: SpeechChannel; whereToStop: LongInt): OSErr;
  9325. FUNCTION ContinueSpeech    (chan: SpeechChannel): OSErr;
  9326. Obtaining Information About Voices
  9327. FUNCTION MakeVoiceSpec    (creator: OSType; id: OSType; voice:VoiceSpecPtr): OSErr;
  9328. FUNCTION CountVoices    (VAR numVoices: Integer): OSErr;
  9329. FUNCTION GetIndVoice    (index: Integer; voice: VoiceSpecPtr): OSErr;
  9330. FUNCTION GetVoiceDescription
  9331. (voice: VoiceSpecPtr; info:VoiceDescriptionPtr; infoLength:LongInt)
  9332. : OSErr;
  9333. FUNCTION GetVoiceInfo    (voice: VoiceSpecPtr; selector:OSType; voiceInfo:Ptr): OSErr;
  9334. Managing Speech Channels
  9335. FUNCTION NewSpeechChannel    (voice: VoiceSpecPtr; VAR chan:SpeechChannel): OSErr;
  9336. FUNCTION DisposeSpeechChannel
  9337. (chan: SpeechChannel): OSErr;
  9338. Obtaining Information About Speech
  9339. FUNCTION SpeechManagerVersion
  9340. : NumVersion;
  9341. FUNCTION SpeechBusy    : Integer;
  9342. FUNCTION SpeechBusySystemWide
  9343. : Integer;
  9344. Changing Speech Attributes
  9345. FUNCTION GetSpeechRate    (chan: SpeechChannel; VAR rate: Fixed): OSErr;
  9346. FUNCTION SetSpeechRate    (chan: SpeechChannel; rate: Fixed): OSErr;
  9347. FUNCTION GetSpeechPitch    (chan: SpeechChannel; VAR pitch: Fixed): OSErr;
  9348. FUNCTION SetSpeechPitch    (chan: SpeechChannel; pitch: Fixed): OSErr;
  9349. FUNCTION GetSpeechInfo    (chan: SpeechChannel; selector: OSType; speechInfo:Ptr): OSErr;
  9350. FUNCTION SetSpeechInfo    (chan: SpeechChannel; selector: OSType; speechInfo:Ptr): OSErr;
  9351. Converting Text to Phonemes
  9352. FUNCTION TextToPhonemes    (chan: SpeechChannel; textBuf:Ptr; textBytes:LongInt; phonemeBuf: Handle; 
  9353. VAR phonemeBytes: LongInt): OSErr;
  9354. Installing a Pronunciation Dictionary
  9355. FUNCTION UseDictionary    (chan: SpeechChannel; dictionary: Handle)
  9356. : OSErr;
  9357. Application-Defined Routines
  9358.  
  9359. PROCEDURE MyTextDoneCallback
  9360. (chan: SpeechChannel; refCon: LongInt; VARnextBuf: Ptr; VAR byteLen: LongInt; VARcontrolFlags: LongInt);
  9361. PROCEDURE MySpeechDoneCallback
  9362. (chan: SpeechChannel; refCon: LongInt);
  9363. PROCEDURE MySynchronizationCallback
  9364. (chan: SpeechChannel; refCon: LongInt; syncMessage: OSType);
  9365. PROCEDURE MyErrorCallback    (chan: SpeechChannel; refCon: LongInt;
  9366. error: OSErr; bytePos: LongInt);
  9367. PROCEDURE MyPhonemeCallback
  9368. (chan: SpeechChannel; refCon: LongInt; phonemeOpcode: Integer);
  9369. PROCEDURE MyWordCallback    (chan: SpeechChannel; refCon: LongInt;
  9370. wordPos: LongInt; wordLen: Integer);
  9371. C Summary
  9372.  
  9373. Constants
  9374.  
  9375. /*Gestalt selector and response bits for speech attributes*/
  9376. #define gestaltSpeechAttr                                    'ttsc'            /*speech attributes selector*/
  9377. enum {
  9378.     gestaltSpeechMgrPresent                                    = 0        /*Speech Manager is present*/
  9379.     gestaltSpeechHasPPCGlue                                    = 1        /*native glue for PowerPC present*/
  9380. };
  9381. /*Operating System types*/
  9382. #define kTextToSpeechSynthType                                                    'ttsc'            /*synthesizer component */
  9383.                                                                 /* type*/
  9384. #define kTextToSpeechVoiceType                                                    'ttvd'            /*voice resource type*/
  9385. #define kTextToSpeechVoiceFileType                                                    'ttvf'            /*voice file type*/
  9386. #define kTextToSpeechVoiceBundleType                                                    'ttvb'            /*voice bundle file type*/
  9387. /*masks for SpeakBuffer and text-done callback control flags*/
  9388. enum {
  9389.     kNoEndingProsody                                = 1,            /*disable prosody at end of sentences*/
  9390.     kNoSpeechInterrupt                                = 2,            /*do not interrupt current speech*/
  9391.     kPreflightThenPause                                = 4            /*compute speech without generating*/
  9392. };
  9393. /*constants for StopSpeechAt and PauseSpeechAt*/
  9394. enum {
  9395.     kImmediate                        = 0,                    /*stop immediately*/
  9396.     kEndOfWord                        = 1,                    /*stop at end of word*/
  9397.     kEndOfSentence                        = 2                    /*stop at end of sentence*/
  9398. };
  9399. /*GetSpeechInfo and SetSpeechInfo selectors*/
  9400. #define soCharacterMode                                        'char'            /*get or set character-processing */
  9401.                                                     /* mode*/
  9402. #define soCommandDelimiter                                        'dlim'            /*set embedded command delimiters*/
  9403. #define soCurrentA5                                        'myA5'            /*set A5 on callbacks*/
  9404. #define soCurrentVoice                                        'cvox'            /*set speaking voice*/
  9405. #define soErrorCallBack                                        'ercb'            /*set error callback*/
  9406. #define soErrors                                        'erro'            /*get error information*/
  9407. #define soInputMode                                        'inpt'            /*get or set text-processing mode*/
  9408. #define soNumberMode                                        'nmbr'            /*get or set number-processing mode*/
  9409. #define soPhonemeCallBack                                        'phcb'            /*set phoneme callback*/
  9410. #define soPhonemeSymbols                                        'phsy'            /*get phoneme symbols and sample*/
  9411.                                                     /* words*/
  9412. #define soPitchBase                                        'pbas'            /*get or set baseline pitch*/
  9413. #define soPitchMod                                        'pmod'            /*get or set pitch modulation*/
  9414. #define soRate                                        'rate'            /*get or set speech rate*/
  9415. #define soRecentSync                                        'sync'            /*get most recent synchronization */
  9416.                                                     /* message information*/
  9417. #define soRefCon                                        'refc'            /*set reference constant value*/
  9418. #define soReset                                        'rset'            /*set channel back to default state*/
  9419. #define soSpeechDoneCallBack                                        'sdcb'            /*set speech-done callback*/
  9420. #define soStatus                                        'stat'            /*get status of channel*/
  9421. #define soSyncCallBack                                        'sycb'            /*set synchronization callback*/
  9422. #define soSynthExtension                                        'xtnd'            /*get or set synthesizer-specific */
  9423.                                                     /* information*/
  9424. #define soSynthType                                        'vers'            /*get synthesizer information*/
  9425. #define soTextDoneCallBack                                        'tdcb'            /*set text-done callback*/
  9426. #define soVolume                                        'volm'            /*get or set speech volume*/
  9427. #define soWordCallBack                                        'wdcb'            /*set word callback*/
  9428. /*input mode constants*/
  9429. #define modeText                                'TEXT'
  9430. #define modePhonemes                                'PHON'
  9431. /*character and number mode constants*/
  9432. #define modeNormal                                'NORM'
  9433. #define modeLiteral                                'LTRL'
  9434. /*GetVoiceInfo selectors*/
  9435. enum {
  9436.     soVoiceDescription                            = 'info',                /*get basic voice information*/
  9437.     soVoiceFile                            = 'fref'                /*get voice file reference information*/
  9438. };
  9439. /*genders*/
  9440. enum {
  9441.     kNeuter = 0, 
  9442.     kMale, 
  9443.     kFemale
  9444. };
  9445. Data Types
  9446.  
  9447. Speech Channel Record
  9448. typedef struct SpeechChannelRecord {
  9449.     long data[1];                                                /*used internally*/
  9450. } SpeechChannelRecord;
  9451. typedef SpeechChannelRecord *SpeechChannel;
  9452. Voice Specification Record
  9453. typedef struct VoiceSpec {
  9454.     OSType                creator;                            /*ID of required synthesizer*/
  9455.     OSType                id;                            /*ID of voice on the synthesizer*/
  9456. } VoiceSpec;
  9457. Voice Description Record
  9458. typedef struct VoiceDescription {
  9459.     long                length;                            /*size of structure--set by application*/
  9460.     VoiceSpec                voice;                            /*voice synthesizer and ID info*/
  9461.     long                version;                            /*version number of voice*/
  9462.     Str63                name;                            /*name of voice*/
  9463.     Str255                comment;                            /*text information about voice*/
  9464.     short                gender;                            /*neuter, male, or female*/
  9465.     short                age;                            /*approximate age in years*/
  9466.     short                script;                            /*script code of text voice can process*/
  9467.     short                language;                            /*language code of voice output*/
  9468.     short                region;                            /*region code of voice output*/
  9469.     long                reserved[4];                            /*always 0--reserved for future use*/
  9470. } VoiceDescription;
  9471. Voice File Information Record
  9472. typedef struct VoiceFileInfo {
  9473.     FSSpec                fileSpec;                            /*volume, dir, and name of file*/
  9474.     short                resID;                            /*resource ID of voice in the file*/
  9475. } VoiceFileInfo;
  9476. Speech Status Information Record
  9477. typedef struct SpeechStatusInfo {
  9478.     Boolean                outputBusy;                            /*TRUE if audio is playing*/
  9479.     Boolean                outputPaused;                            /*TRUE if channel is paused*/
  9480.     long                inputBytesLeft;                            /*bytes of text left to process*/
  9481.     short                phonemeCode;                            /*opcode for current phoneme*/
  9482. } SpeechStatusInfo;
  9483. Speech Error Information Record
  9484. typedef struct SpeechErrorInfo {
  9485.     short                count;                            /*number of errors since last check*/
  9486.     OSErr                oldest;                            /*oldest unread error*/
  9487.     long                oldPos;                            /*character position of oldest error*/
  9488.     OSErr                newest;                            /*most recent error*/
  9489.     long                newPos;                            /*character position of newest error*/
  9490. } SpeechErrorInfo;
  9491. Speech Version Information Record
  9492. typedef struct SpeechVersionInfo {
  9493.     OSType                synthType;                            /*general synthesizer type*/
  9494.     OSType                synthSubType;                            /*specific synthesizer type*/
  9495.     OSType                synthManufacturer;                            /*synthesizer creator ID*/
  9496.     long                synthFlags;                            /*synthesizer feature flags*/
  9497.     NumVersion                synthVersion;                            /*synthesizer version number*/
  9498. } SpeechVersionInfo;
  9499. Phoneme Information Record
  9500. typedef struct PhonemeInfo {
  9501.     short                opcode;                            /*opcode for the phoneme*/
  9502.     Str15                phStr;                            /*corresponding character string*/
  9503.     Str31                exampleStr;                            /*word that shows use of phoneme*/
  9504.     short                hiliteStart;                            /*offset from beginning of word */
  9505.                                                 /* to beginning of phoneme sound*/
  9506.     short                hiliteEnd;                            /*offset from beginning of word */
  9507.                                                 /* to end of phoneme sound*/
  9508. } PhonemeInfo;
  9509. Phoneme Descriptor Record
  9510. typedef struct PhonemeDescriptor {
  9511.     short                    phonemeCount;                        /*number of phonemes defined by */
  9512.                                                 /* current synthesizer*/
  9513.     PhonemeInfo                    thePhonemes[1];                        /*list of phoneme information records*/
  9514. } PhonemeDescriptor;
  9515. Speech Extension Data Record
  9516. typedef struct SpeechXtndData {
  9517.     OSType                synthCreator;                            /*synthesizer creator ID*/
  9518.     Byte                synthData[2];                            /*data used by synthesizer*/
  9519. } SpeechXtndData;
  9520. Delimiter Information Record
  9521. typedef struct DelimiterInfo {
  9522.     Byte                startDelimiter[2];                            /*start delimiter*/
  9523.     Byte                endDelimiter[2];                            /*end delimiter*/
  9524. } DelimiterInfo;
  9525. Speech Manager Routines
  9526.  
  9527. Starting, Stopping, and Pausing Speech
  9528. pascal OSErr SpeakString    (StringPtr s);
  9529. pascal OSErr SpeakText    (SpeechChannel chan, Ptr textBuf, 
  9530. long textBytes);
  9531. pascal OSErr SpeakBuffer    (SpeechChannel chan, Ptr textBuf, 
  9532. long textBytes, long controlFlags);
  9533. pascal OSErr StopSpeech    (SpeechChannel chan);
  9534. pascal OSErr StopSpeechAt    (SpeechChannel chan, long whereToStop);
  9535. pascal OSErr PauseSpeechAt    (SpeechChannel chan, long whereToPause);
  9536. pascal OSErr ContinueSpeech
  9537. (SpeechChannel chan);
  9538. Obtaining Information About Voices
  9539. pascal OSErr MakeVoiceSpec    (OSType creator, OSType id, VoiceSpec *voice);
  9540. pascal OSErr CountVoices    (short *numVoices);
  9541. pascal OSErr GetIndVoice    (short index, VoiceSpec *voice);
  9542. pascal OSErr GetVoiceDescription
  9543. (VoiceSpec *voice, VoiceDescription *info,
  9544. long infoLength);
  9545. pascal OSErr GetVoiceInfo    (VoiceSpec *voice, OSType selector, 
  9546. void *voiceInfo);
  9547. Managing Speech Channels
  9548. pascal OSErr NewSpeechChannel
  9549. (VoiceSpec *voice, SpeechChannel *chan);
  9550. pascal OSErr DisposeSpeechChannel
  9551. (SpeechChannel chan);
  9552. Obtaining Information About Speech
  9553. pascal NumVersion SpeechManagerVersion
  9554. (void);
  9555. pascal short SpeechBusy    (void);
  9556. pascal short SpeechBusySystemWide
  9557. (void);
  9558. Changing Speech Attributes
  9559. pascal OSErr GetSpeechRate    (SpeechChannel chan, Fixed *rate);
  9560. pascal OSErr SetSpeechRate    (SpeechChannel chan, Fixed rate);
  9561. pascal OSErr GetSpeechPitch
  9562. (SpeechChannel chan, Fixed *pitch);
  9563. pascal OSErr SetSpeechPitch
  9564. (SpeechChannel chan, Fixed pitch);
  9565. pascal OSErr GetSpeechInfo    (SpeechChannel chan, OSType selector, 
  9566. void *speechInfo);
  9567. pascal OSErr SetSpeechInfo    (SpeechChannel chan, OSType selector, 
  9568. void *speechInfo);
  9569. Converting Text to Phonemes
  9570. pascal OSErr TextToPhonemes
  9571. (SpeechChannel chan, Ptr textBuf, 
  9572. long textBytes, Handle phonemeBuf, 
  9573. long *phonemeBytes);
  9574. Installing a Pronunciation Dictionary
  9575. pascal OSErr UseDictionary    (SpeechChannel chan, Handle dictionary);
  9576. Application-Defined Routines
  9577.  
  9578. #pragma procname SpeechTextDone
  9579. typedef pascal void (*SpeechTextDoneCBPtr) 
  9580. (SpeechChannel, long, Ptr *, long *, long *);
  9581. typedef SpeechTextDoneProcPtr SpeechTextDoneCBPtr;
  9582. #pragma procname SpeechDone
  9583. typedef pascal void (*SpeechDoneCBPtr)
  9584. (SpeechChannel, long);
  9585. typedef SpeechDoneProcPtr SpeechDoneCBPtr;
  9586. #pragma procname SpeechSync
  9587. typedef pascal void (*SpeechSyncCBPtr)
  9588. (SpeechChannel, long, OSType);
  9589. typedef SpeechSyncProcPtr SpeechSyncCBPtr;
  9590. #pragma procname SpeechError
  9591. typedef pascal void (*SpeechErrorCBPtr)
  9592. (SpeechChannel, long, OSErr, long);
  9593. typedef SpeechErrorProcPtr SpeechErrorCBPtr;
  9594. #pragma procname SpeechPhoneme
  9595. typedef pascal void (*SpeechPhonemeCBPtr)
  9596. (SpeechChannel, long, short);
  9597. typedef SpeechPhonemeProcPtr SpeechPhonemeCBPtr;
  9598. #pragma procname SpeechWord
  9599. typedef pascal void (*SpeechWordCBPtr)
  9600. (SpeechChannel, long, long, short);
  9601. typedef SpeechWordProcPtr SpeechWordCBPtr;
  9602. Assembly-Language Information
  9603.  
  9604. Data Structures
  9605.  
  9606. Voice Specification Data Structure0    creator    4 bytes    ID of required synthesizer    
  9607. 4    id    4 bytes    ID of voice on the synthesizer    
  9608.  
  9609. Voice Description Data Structure0    length    long    size of structure—set by application    
  9610. 4    voice    8 bytes    voice specification record    
  9611. 12    version    long    version number of voice    
  9612. 16    name    64 bytes    name of voice; preceded by length byte    
  9613. 80    comment    256 bytes    text information about voice; preceded by length byte    
  9614. 336    gender    short    neuter (0), male (1), or female (2)    
  9615. 338    age    short    approximate age in years    
  9616. 340    script    short    script code of text voice can process    
  9617. 342    language    short    language code of text voice can process    
  9618. 344    region    short    region code of voice output    
  9619. 346    reserved    16 bytes    always set to 0—reserved for future use    
  9620.  
  9621. Voice File Information Data Structure0    fileSpec    70 bytes    volume, directory, and name of file    
  9622. 70    resID    word    resource ID of voice in the file    
  9623.  
  9624. Speech Status Information Data Structure0    outputBusy    byte    1 if audio is playing    
  9625. 1    outputPaused    byte    1 if channel is paused    
  9626. 2    inputBytesLeft    long    bytes of text left to process    
  9627. 6    phonemeCode    short    opcode for current phoneme    
  9628.  
  9629. Speech Error Information Data Structure0    count    word    number of errors since last check    
  9630. 2    oldest    long    oldest unread Operating System error    
  9631. 6    oldPos    long    character position of oldest error    
  9632. 10    newest    long    newest Operating System error    
  9633. 14    newPos    long    character position of newest error    
  9634.  
  9635. Speech Version Information Data Structure0    synthType    4 bytes    always 'TTSC'    
  9636. 4    synthSubType    4 bytes    synthesizer type    
  9637. 8    synthManufacturer    4 bytes    synthesizer creator ID    
  9638. 12    synthFlags    long    synthesizer feature flags    
  9639. 16    synthVersion    long    synthesizer version number    
  9640.  
  9641. Phoneme Information Data Structure0    opcode    word    opcode for the phoneme    
  9642. 2    phStr    16 bytes    corresponding character string; preceded by length byte    
  9643. 18    exampleStr    32 bytes    word that shows use of phoneme    
  9644. 50    hiliteStart    word    offset from beginning of word to beginning of phoneme sound    
  9645. 52    hiliteEnd    word    offset from beginning of word to end of phoneme sound    
  9646.  
  9647. Phoneme Descriptor Data Structure0    phonemeCount    word    number of phonemes defined by current synthesizer    
  9648. 2    thePhonemes    variable    list of phoneme information records    
  9649.  
  9650. Speech Extension Data Structure0    synthCreator    4 bytes    synthesizer creator ID    
  9651. 4    synthData    variable    data used by synthesizer    
  9652.  
  9653. Delimiter Information Data Structure0    startDelimiter    2 bytes    start embedded command characters; defaults to “[[”    
  9654. 2    endDelimiter    2 bytes    end embedded command characters; defaults to “]]”    
  9655.  
  9656. Trap Macros
  9657.  
  9658. Trap Macro Requiring Routine Selectors
  9659. _SoundDispatch
  9660. Selector    Routine    
  9661. $0000000C    SpeechManagerVersion    
  9662. $003C000C    SpeechBusy    
  9663. $0040000C    SpeechBusySystemWide    
  9664. $0108000C    CountVoices    
  9665. $021C000C    DisposeSpeechChannel    
  9666. $0220000C    SpeakString    
  9667. $022C000C    StopSpeech    
  9668. $0238000C    ContinueSpeech    
  9669. $030C000C    GetIndVoice    
  9670. $0418000C    NewSpeechChannel    
  9671. $0430000C    StopSpeechAt    
  9672. $0434000C    PauseSpeechAt    
  9673. $0444000C    SetSpeechRate    
  9674. $0448000C    GetSpeechRate    
  9675. $044C000C    SetSpeechPitch    
  9676. $0450000C    GetSpeechPitch    
  9677. $0460000C    UseDictionary    
  9678. $0604000C    MakeVoiceSpec    
  9679. $0610000C    GetVoiceDescription    
  9680. $0614000C    GetVoiceInfo    
  9681. $0624000C    SpeakText    
  9682. $0654000C    SetSpeechInfo    
  9683. $0658000C    GetSpeechInfo    
  9684. $0828000C    SpeakBuffer    
  9685. $0A5C000C    TextToPhonemes    
  9686.  
  9687. Result CodesnoErr    0    No error    
  9688. paramErr    –50    Parameter error    
  9689. memFullErr    –108    Not enough memory to speak    
  9690. nilHandleErr    –109    Handle argument is NIL    
  9691. siUnknownInfoType    –231    Feature not implemented on synthesizer    
  9692. noSynthFound    –240    Could not find the specified speech synthesizer    
  9693. synthOpenFailed    –241    Could not open another speech synthesizer channel    
  9694. synthNotReady    –242    Speech synthesizer is still busy speaking    
  9695. bufTooSmall    –243    Output buffer is too small to hold result    
  9696. voiceNotFound    –244    Voice resource not found    
  9697. incompatibleVoice    –245    Specified voice cannot be used with synthesizer    
  9698. badDictFormat    –246    Pronunciation dictionary format error    
  9699. badPhonemeText    –247    Raw phoneme text contains invalid characters    
  9700. unimplMsg    –248    Unimplemented message    
  9701. badVoiceID    –250    Specified voice has not been preloaded    
  9702. badParmCount    –252    Incorrect number of embedded command arguments    
  9703. invalidComponentID    –3000    Speech channel is uninitialized or bad    
  9704.  
  9705.  
  9706.  
  9707. Listing 5-0
  9708. Table 5-0
  9709. Sound Components
  9710. Contents
  9711. About Sound Components5-4
  9712. Sound Component Chains5-4
  9713. The Apple Mixer5-6
  9714. The Data Stream5-7
  9715. Writing a Sound Component5-8
  9716. Creating a Sound Component5-8
  9717. Specifying Sound Component Capabilities5-11
  9718. Dispatching to Sound Component-Defined Routines5-12
  9719. Registering and Opening a Sound Component5-16
  9720. Finding and Changing Component Capabilities5-18
  9721. Sound Components Reference5-22
  9722. Constants5-22
  9723. Sound Component Information Selectors5-22
  9724. Audio Data Types5-26
  9725. Sound Component Features Flags5-26
  9726. Action Flags5-27
  9727. Data Format Flags5-28
  9728. Data Structures5-29
  9729. Sound Component Data Records5-29
  9730. Sound Parameter Blocks5-30
  9731. Sound Information Lists5-31
  9732. Compression Information Records5-32
  9733. Sound Manager Utilities5-33
  9734. Opening and Closing the Apple Mixer Component5-33
  9735. Saving and Restoring Sound Component Preferences5-35
  9736. Sound Component-Defined Routines5-36
  9737. Managing Sound Components5-37
  9738. Creating and Removing Audio Sources5-42
  9739. Getting and Setting Sound Component Information5-44
  9740. Managing Source Data5-46
  9741. Summary of Sound Components5-50
  9742. C Summary5-50
  9743. Constants5-50
  9744. Data Types5-53
  9745. Sound Manager Utilities5-54
  9746. Sound Component-Defined Routines5-55
  9747. Assembly-Language Summary5-56
  9748. Data Structures5-56
  9749. Sound Components
  9750. This chapter describes sound components, which are code modules used by the Sound Manager to manipulate audio data or to communicate with sound output devices. Current versions of the Sound Manager allow you to write two kinds of sound components:
  9751. n    compression and decompression components (codecs), which allow you to implement audio data compression and decompression algorithms different from those provided by the Sound Manager’s MACE (Macintosh Audio Compression and Expansion) capabilities
  9752. n    sound output device components, which send audio data directly to sound output devices
  9753. You need to read this chapter only if you are developing a sound output device or if you want to implement a custom compression and decompression scheme for audio data. For example, you might write a codec to handle 16-bit audio data compression and decompression. (The MACE algorithms currently compress and expand only 8-bit data at ratios of 3:1 and 6:1.)
  9754. IMPORTANT
  9755. Sound components are loaded and managed by the Sound Manager and operate transparently to applications. Applications that want to create sounds must use Sound Manager routines to do so. The routines described in this chapter are intended for use exclusively by sound components.s
  9756. To use this chapter, you should already be familiar with the general operation of the Sound Manager, as described in the chapter “Introduction to Sound on the Macintosh” in this book. Because sound components are components, you also need to be familiar with the Component Manager, described in Inside Macintosh: More Macintosh Toolbox. If you are developing a sound output device component, you need to be familiar with the process of installing a driver and handling interrupts created by your hardware device. See Inside Macintosh: Devices for complete information on devices and device drivers.
  9757. If you’re developing a sound output device, you might also need to write a control panel extension that installs a custom subpanel into the Sound control panel. For example, your subpanel could allow the user to set various characteristics of the sound your output device is creating. For complete information on writing control panel subpanels, see the chapter “Control Panel Extensions” in Inside Macintosh: Operating System Utilities.
  9758. This chapter begins with a general description of sound components and how they are managed by the Sound Manager. Then it provides instructions on how to write a sound component. The section “Sound Components Reference” beginning on page 5-22 describes the sound component selectors your component might need to handle and the component-defined routines that your sound component should call in response to those the sound component selectors. It also describes a small number of Sound Manager utility routines that your sound component can use.
  9759. Note
  9760. Note
  9761. Pascal interfaces for sound components are not currently available. As a result, this chapter provides all source code examples and reference materials in C.u
  9762.  
  9763. About Sound Components
  9764.  
  9765. A sound component is a component that works with the Sound Manager to manipulate audio data or to communicate with a sound output device. Sound components provide the foundation for the modular, device-independent sound architecture introduced with Sound Manager version 3.0. This section provides a description of sound components and shows how they are managed by the Sound Manager. For specific information on creating a sound component, see “Writing a Sound Component” beginning on page 5-8.
  9766. Sound Component Chains
  9767.  
  9768. Prior to version 3.0, the Sound Manager performed all audio data processing internally, using its own filters to decompress audio data, convert sample rates, mix separate sound channels, and so forth. This effectively rendered it difficult, if not impossible, to add other data modification filters to process the audio data. (The now-obsolete method of installing a sound modifier with the SndAddModifier routine did not work reliably.) More importantly, the Sound Manager was responsible for managing the entire stream of audio data, from the application to the available sound-producing audio hardware. This made it very difficult to support new sound output devices.
  9769. In versions 3.0 and later, the Sound Manager provides a new audio data processing architecture based on components, illustrated in Figure 5-1. The fundamental idea is that the process of playing a sound can be divided into a number of specific steps, each of which has well-defined inputs and outputs. Figure 5-1 shows the steps involved in playing an 11 kHz compressed sampled sound resource on a Macintosh II computer.
  9770. An application sends the compressed sound data to the Sound Manager, which constructs an appropriate sound component chain that links the unprocessed audio data to the sound components required to modify the data into a form that can be sent to the current sound output device. As you can see in Figure 5-1, the Sound Manager links together sound components that, in sequence, expand the compressed sound data into audio samples, convert the sample rate from 11 kHz to 22 kHz, mix those samples with samples from any other sound channels that might be playing, and then write the samples to the available audio hardware (in this case, the FIFO buffer in the Apple Sound Chip).
  9771. IMPORTANT
  9772. The Sound Manager itself converts both wave-table data and square-wave data into sampled-sound data before sending the data into a chain of sound components. As a result, sound components need to be concerned only with sampled-sound data.s
  9773. Figure 5-1    The component-based sound architecture
  9774.  
  9775. The components in a component chain may vary, depending both on the format of the audio data sent to the Sound Manager by an application and on the capabilities of the current sound output device. The chain shown in Figure 5-1 is necessary to handle the compressed 11 kHz sound because the Apple Sound Chip can handle only 22 kHz noncompressed sampled-sound data. Other sound output devices may be able to do more processing internally, thereby reducing the amount of processing required by the sound component chain. For instance, a DSP-based sound card might be capable of converting sample rates itself. In that case, the Sound Manager would not install the rate conversion component into the sound component chain. The resulting sound component chain is shown in Figure 5-2.
  9776. Figure 5-2    A component chain for audio hardware that can convert sample rates
  9777.  
  9778. The principal function of a sound component is to transfer data from the source down the chain of sound components while performing some specific modification on the data. It does this by getting a block of data from its source component (the component that immediately precedes it in the chain). The sound component then processes that data and stores it in the component’s own private buffers. The next component can then get that processed data, perform its own modifications, and pass the data to the next component in the chain. Eventually, the audio data flows through the Apple Mixer (described in the next section) to the sound output device component, which sends the data to the current sound output device.
  9779. Notice that only the sound output device component communicates directly with the sound output hardware. This insulates all other sound components from having to know anything about the current sound output device. Rather, those components (sometimes called utility components) can simply operate on a stream of bytes.
  9780. The Sound Manager provides sound output device components for all sound output devices built into Macintosh computers. It also provides utility components for many typical kinds of audio data manipulation, including
  9781. n    sample rate conversion
  9782. n    audio data expansion
  9783. n    sample size conversion
  9784. n    format conversion (for example, converting offset binary data to two’s complement)
  9785. Currently, you can write sound output device components to handle communication with your own sound output devices. You can also write utility components to handle custom compression and expansion schemes. You cannot currently write any other kind of utility component.
  9786. The Apple Mixer
  9787.  
  9788. As you’ve seen, most sound components take a single source of audio data and modify it in some way, thereby producing a single output stream of audio data. There is one special sound component, known as the Apple Mixer component (or, more briefly, the Apple Mixer), that is able to handle more than one input data stream. Its function is precisely to mix together all open channels of sound data into a single output stream, as shown in Figure 5-3.
  9789. Figure 5-3    Mixing multiple channels of sound
  9790.  
  9791. The Apple Mixer has a more general function also, namely to construct the sound component chain required to process audio data from a given sound source into a format that can be handled by a particular sound output device. The Apple Mixer always feeds its output directly to the sound output device component, which sends the data to its associated audio hardware. After creating the component chain, the Apple Mixer assigns it a source ID, a 4-byte token that provides a unique reference to the component chain. The Apple Mixer is actually created by the sound output device component, when that component calls the Sound Manager’s OpenMixerSoundComponent function.
  9792. In addition to creating sound component chains and mixing their data, the Apple Mixer can control the volume and stereo panning of a particular sound channel. Some sound output devices might be able to provide these capabilities as well. Indeed, some sound output devices might even be able to mix the data in multiple sound channels. In those cases, the sound output device component can call the OpenMixerSoundComponent function once for each sound source it wants to manage. The result is a separate instance of the Apple Mixer for each sound source, as shown in Figure 5-4.
  9793. Figure 5-4    A sound output device component that can mix sound channels
  9794.  
  9795. The sound output device component can instruct each instance of the Apple Mixer to pass all the sound data through unprocessed, thereby allowing the output device to perform the necessary processing and mixing. In this case, the Apple Mixer consumes virtually no processing time. The Apple Mixer must, however, still be present to set up the sound component chain and to assign a source ID to each sound source.
  9796. The Data Stream
  9797.  
  9798. A sound component is a standalone code resource that performs some signal processing function or communicates with a sound output device. All sound components have a standard programming interface and local storage that allows them to be connected together in series to perform a wide range of audio data processing tasks. As previously indicated, all sound components (except for mixer components and some sound output device components) accept a single stream of input data and produce a single stream of output data.
  9799. The Sound Manager sends your sound component information about its input stream by passing it the address of a sound component data record, defined by the SoundComponentData data type.
  9800. typedef struct {
  9801.     long                    flags;                    /*sound component flags*/
  9802.     OSType                    format;                    /*data format*/
  9803.     short                    numChannels;                    /*number of channels in data*/
  9804.     short                    sampleSize;                    /*size of a sample*/
  9805.     UnsignedFixed                    sampleRate;                    /*sample rate*/
  9806.     long                    sampleCount;                    /*number of samples in buffer*/
  9807.     Byte                    *buffer;                    /*location of data*/
  9808.     long                    reserved;                    /*reserved*/
  9809. } SoundComponentData, *SoundComponentDataPtr;
  9810. The buffer field points to the buffer of input data. The other fields define the format of that data. For example, the sample size and rate are passed in the sampleSize and sampleRate fields, respectively. A utility component should modify the data in that buffer and then write the processed data into an internal buffer. Then it should fill out a sound component data record and pass its address back to the Sound Manager, which will then pass it on to the next sound component in the chain. Eventually, the audio data passes through all utility components in the chain, through the Apple Mixer and the sound output device component, down to the audio hardware.
  9811.  
  9812. Writing a Sound Component
  9813.  
  9814. A sound component is a component that works with the Sound Manager to manipulate audio data or to communicate with a sound output device. Because a sound component is a component, it must be able to respond to standard selectors sent by the Component Manager. In addition, a sound component must handle other selectors specific to sound components. This section describes how to write a sound component.
  9815. Creating a Sound Component
  9816.  
  9817. A sound component is a component. It contains a number of resources, including icons, strings, and the standard component resource (a resource of type 'thng') required of any Component Manager component. In addition, a sound component must contain code to handle required selectors passed to it by the Component Manager as well as selectors specific to the sound component.
  9818. Note
  9819. Note
  9820. For complete details on components and their structure, see the chapter “Component Manager” in Inside Macintosh: More Macintosh Toolbox. This section provides specific information about sound components.u
  9821. The component resource binds together all the relevant resources contained in a component; its structure is defined by the ComponentResource data type.
  9822. struct ComponentResource {
  9823.     ComponentDescription                                 cd;
  9824.     ResourceSpec                                 component;
  9825.     ResourceSpec                                 componentName
  9826.     ResourceSpec                                componentInfo;
  9827.     ResourceSpec                                componentIcon;
  9828. };
  9829. The component field specifies the resource type and resource ID of the component’s executable code. By convention, this field should be set to the value kSoundComponentCodeType:
  9830. #define kSoundComponentCodeType                                                'sift'            /*sound component code type*/
  9831. (You can, however, specify some other resource type if you wish.) The resource ID can be any integer greater than or equal to 128. See the following section for further information about this code resource. The ResourceSpec data type has this structure:
  9832. typedef struct {
  9833.     OSType                                resType;
  9834.     short                                resID;
  9835. } ResourceSpec;
  9836. The componentName field specifies the resource type and resource ID of the resource that contains the component’s name. Usually the name is contained in a resource of type 'STR '. This string should be as short as possible.
  9837. The componentInfo field specifies the resource type and resource ID of the resource that contains a description of the component. Usually the description is contained in a resource of type 'STR '.
  9838. The componentIcon field specifies the resource type and resource ID of the resource that contains an icon for the component. Usually the icon is contained in a resource of type 'ICON'.
  9839. The cd field of the ComponentResource structure is a component description record, which contains additional information about the component. A component description record is defined by the ComponentDescription data type.
  9840. typedef struct {
  9841.     OSType                                componentType;
  9842.     OSType                                componentSubType;
  9843.     OSType                                componentManufacturer;
  9844.     unsigned long                                componentFlags;
  9845.     unsigned long                                componentFlagsMask;
  9846. } ComponentDescription;
  9847. For sound components, the componentType field must be set to a value recognized by the Sound Manager. Currently, there are five available component types for sound components:
  9848. #define kSoundComponentType                                            'sift'            /*utility component*/
  9849. #define kMixerType                                            'mixr'            /*mixer component*/
  9850. #define kSoundHardwareType                                            'sdev'            /*sound output device component*/
  9851. #define kSoundCompressor                                            'scom'            /*compression component*/
  9852. #define kSoundDecompressor                                            'sdec'            /*decompression component*/
  9853. In addition, the componentSubType field must be set to a value that indicates the type of audio services your component provides. For example, the Apple-supplied sound output device components have these subtypes:
  9854. #define kClassicSubType                                            'clas'            /*Classic hardware*/
  9855. #define kASCSubType                                            'asc '            /*ASC device*/
  9856. #define kDSPSubType                                            'dsp '            /*DSP device*/
  9857. If you add your own sound output device component, you should define some other subtype.
  9858. Note
  9859. Apple Computer, Inc., reserves for its own use all types and subtypes composed solely of lowercase letters.u
  9860. You can assign any value you like to the componentManufacturer field; typically you put the signature of your sound component in this field.
  9861. The componentFlags field of the component description for a sound component contains bit flags that encode information about the component. You can use this field to specify that the Component Manager should send your component the kComponentRegisterSelect selector.
  9862. enum {
  9863.     cmpWantsRegisterMessage                                    = 1L<<31            /*send register request*/
  9864. };
  9865. This bit is most useful for sound output device components, which might need to test for the presence of the appropriate hardware to determine whether to register with the Component Manager. When your component gets the kComponentRegisterSelect selector at system startup time, it should make sure that all the necessary hardware is available. If it isn’t available, your component shouldn’t register. See “Registering and Opening a Sound Component” beginning on page 5-16 for more information on opening and registering your sound component.
  9866. You also use the componentFlags field of the component description to define the characteristics of your component. For example, you can set a bit in that field to indicate that your sound component can accept stereo sound data. See “Specifying Sound Component Capabilities” on page 5-11 for more details on specifying the features of your sound component.
  9867. You should set the componentFlagsMask field to 0.
  9868. Listing 5-1 shows, in Rez format, a component resource for a sample sound output device component named SurfBoard.
  9869. Listing 5-1    Rez input for a component resource
  9870.  
  9871. #define kSurfBoardID                                                        128
  9872. #define kSurfBoardSubType                                                        'SURF'
  9873. resource 'thng' (kSurfBoardID, purgeable) {
  9874.     'sdev',                                        /*component type*/
  9875.     kSurfBoardSubType,                                        /*component subtype*/
  9876.     'appl',                                        /*component manufacturer*/
  9877.     cmpWantsRegisterMessage,                                        /*component flags*/
  9878.     0,                                        /*component flags mask*/
  9879.     'sift',                                        /*component code resource type*/
  9880.     kSurfBoardID,                                        /*component code resource ID*/
  9881.     'STR ',                                        /*component name resource type*/
  9882.     kSurfBoardID,                                        /*component name resource ID*/
  9883.     'STR ',                                        /*component info resource type*/
  9884.     kSurfBoardID+1,                                        /*component info resource ID*/
  9885.     'ICON',                                        /*component icon resource type*/
  9886.     kSurfBoardID                                        /*component icon resource ID*/
  9887. };
  9888. Your sound component is contained in a resource file. You can assign any type you wish to be the file creator, but the type of the file must be 'thng'. If the sound component contains a 'BNDL' resource, then the file’s bundle bit must be set.
  9889. Specifying Sound Component Capabilities
  9890.  
  9891. As mentioned in the previous section, the componentFlags field of a component description for a sound component contains bit flags that encode information about the component. The high-order 8 bits of that field are reserved for use by the Component Manager. In those 8 bits, you can set the cmpWantsRegisterMessage bit to indicate that the Component Manger should call your component during registration.
  9892. The low-order 24 bits of the componentFlags field of a component description are used by the Sound Manager. You’ll set some of these bits to define the capabilities of your sound component. You can use the following constants to set specific bits in the componentFlags field.
  9893. #define k8BitRawIn                                            (1 << 0)                /*data flags*/
  9894. #define k8BitTwosIn                                            (1 << 1)
  9895. #define k16BitIn                                            (1 << 2)
  9896. #define kStereoIn                                            (1 << 3)
  9897. #define k8BitRawOut                                            (1 << 8)
  9898. #define k8BitTwosOut                                            (1 << 9)
  9899. #define k16BitOut                                            (1 << 10)
  9900. #define kStereoOut                                            (1 << 11)
  9901. #define kReverse                                            (1 << 16)                /*action flags*/
  9902. #define kRateConvert                                            (1 << 17)
  9903. #define kCreateSoundSource                                            (1 << 18)
  9904. #define kHighQuality                                            (1 << 22)                /*performance flags*/
  9905. #define kRealTime                                            (1 << 23)
  9906. These constants define four types of information about your sound component: the kind of audio data it can accept as input, the kind of audio data it can produce as output, the actions it can perform on the audio data it’s passed, and the performance of your sound component. For example, a utility component that accepts only monaural 8-bit, offset binary data as input and converts it to 16-bit two’s complement data might have the value 0x00000801 (that is, k8BitRawIn | k16BitOut) in the componentFlags field.
  9907. The Sound Manager also defines a number of masks that you can use to select ranges of bits within the componentFlags field. See “Sound Component Features Flags” on page 5-26 for complete information on the defined bit constants and masks.
  9908. Dispatching to Sound Component-Defined Routines
  9909.  
  9910. As explained earlier, the code stored in the sound component should be contained in a resource of type kSoundComponentCodeType. The Component Manager expects the entry point in this resource to be a function with this format:
  9911. pascal ComponentResult MySurfDispatch (ComponentParameters *params, 
  9912.                                                         SoundComponentGlobalsPtr globals);
  9913. The Component Manager calls your sound component by passing MySurfDispatch a selector in the params->what field; MySurfDispatch must interpret the selector and possibly dispatch to some other routine in the resource. Your sound component must be able to handle the required selectors, defined by these constants:
  9914. #define kComponentOpenSelect                                                     -1
  9915. #define kComponentCloseSelect                                                     -2
  9916. #define kComponentCanDoSelect                                                     -3
  9917. #define kComponentVersionSelect                                                     -4
  9918. #define kComponentRegisterSelect                                                     -5
  9919. #define kComponentTargetSelect                                                      -6
  9920. #define kComponentUnregisterSelect                                                     -7
  9921. Note
  9922. For complete details on required component selectors, see the chapter “Component Manager” in Inside Macintosh: More Macintosh Toolbox.u
  9923. In addition, your sound component must be able to respond to component-specific selectors. Some of these selectors must be handled by your component; if your component doesn’t implement one of these selectors, it should return the badComponentSelector result code. Other selectors should be delegated up the component chain. This allows the Sound Manager to query a particular component chain by passing a selector to the first component in the chain. If your component does not implement a delegable selector, it should call the Component Manager routine DelegateComponentCall to delegate the selector to its source component. If your sound component does implement a particular delegable selector, it should perform the operation associated with it. The Sound Manager defines a constant to designate the delegable selectors.
  9924. /*first selector that can be delegated up the chain*/
  9925. #define kDelegatedSoundComponentSelectors                                                                0x0100
  9926. The Sound Manager can pass these selectors to your sound component:
  9927. enum {
  9928.     /*the following calls cannot be delegated*/
  9929.     kSoundComponentInitOutputDeviceSelect                                                        = 1,
  9930.     kSoundComponentSetSourceSelect,
  9931.     kSoundComponentGetSourceSelect,
  9932.     kSoundComponentGetSourceDataSelect,
  9933.     kSoundComponentSetOutputSelect,
  9934.     /*the following calls can be delegated*/
  9935.     kSoundComponentAddSourceSelect = kDelegatedSoundComponentSelectors + 1,
  9936.     kSoundComponentRemoveSourceSelect,
  9937.     kSoundComponentGetInfoSelect,
  9938.     kSoundComponentSetInfoSelect,
  9939.     kSoundComponentStartSourceSelect,
  9940.     kSoundComponentStopSourceSelect,
  9941.     kSoundComponentPauseSourceSelect,
  9942.     kSoundComponentPlaySourceBufferSelect
  9943. };
  9944. You can respond to these selectors by calling the Component Manager routine CallComponentFunctionWithStorage or by delegating the selector to your component’s source component. Listing 5-2 illustrates how to define a sound component entry point routine.
  9945. Listing 5-2    Handling Component Manager selectors
  9946.  
  9947. pascal ComponentResult MySurfDispatch (ComponentParameters *params,
  9948.                                                          SoundComponentGlobalsPtr globals)
  9949. {
  9950.     ComponentRoutine                            myRoutine;
  9951.     ComponentResult                            myResult;
  9952.  
  9953.     /*Get address of component-defined routine.*/
  9954.     myRoutine = MyGetComponentRoutine(params->what);
  9955.  
  9956.     if (myRoutine == nil)                                                        /*selector not implemented*/
  9957.         myResult = badComponentSelector;
  9958.     else if (myRoutine == kDelegateCall)                                                        /*selector should be delegated*/
  9959.         myResult = DelegateComponentCall(params, globals->sourceComponent);
  9960.     else
  9961.         myResult = CallComponentFunctionWithStorage((Handle) globals, params, 
  9962.                                                             (ComponentRoutine) myRoutine);
  9963.     return (myResult);
  9964. }
  9965. As you can see, the MySurfDispatch function defined in Listing 5-2 simply retrieves the address of the appropriate component-defined routine, as determined by the params->what field. If the routine MyGetComponentRoutine returns nil, then MySurfDispatch itself returns the badComponentSelector result code. Otherwise, if the selector should be delegated, MySurfDispatch calls DelegateComponentCall to do so. Finally, if the selector hasn’t yet been handled, the appropriate component-defined routine is executed via CallComponentFunctionWithStorage.
  9966. Listing 5-3 defines the function MyGetComponentRoutine.
  9967. Listing 5-3    Finding the address of a component-defined routine
  9968.  
  9969. ComponentRoutine MyGetComponentRoutine (short selector)
  9970. {
  9971.     void                             *myRoutine;
  9972.  
  9973.     if (selector < 0)
  9974.         switch (selector)                                    /*required component selectors*/
  9975.         {
  9976.             case kComponentRegisterSelect:
  9977.                 myRoutine = MyRegisterSoundComponent;
  9978.                 break;
  9979.             case kComponentVersionSelect:
  9980.                 myRoutine = MySoundComponentVersion;
  9981.                 break;
  9982.             case kComponentCanDoSelect:
  9983.                 myRoutine = MySoundComponentCanDo;
  9984.                 break;
  9985.             case kComponentCloseSelect:
  9986.                 myRoutine = MyCloseSoundComponent;
  9987.                 break;
  9988.             case kComponentOpenSelect:
  9989.                 myRoutine = MyOpenSoundComponent;
  9990.                 break;
  9991.             default:
  9992.                 myRoutine = nil;                            /*unknown selector, so fail*/
  9993.                 break;
  9994.         }
  9995.     else if (selector < kDelegatedSoundComponentSelectors)
  9996.                                     /*selectors that can't be delegated*/
  9997.         switch (selector)
  9998.         {
  9999.             case kSoundComponentInitOutputDeviceSelect:
  10000.                 myRoutine = MySoundComponentInitOutputDevice;
  10001.                 break;
  10002.  
  10003.             case kSoundComponentSetSourceSelect:
  10004.             case kSoundComponentGetSourceSelect:
  10005.             case kSoundComponentGetSourceDataSelect:
  10006.             case kSoundComponentSetOutputSelect:
  10007.             default:
  10008.                 myRoutine = nil;                            /*unknown selector, so fail*/
  10009.                 break;
  10010.         }
  10011.     else                                /*selectors that can be delegated*/
  10012.         switch (selector)
  10013.         {
  10014.             case kSoundComponentStartSourceSelect:
  10015.                 myRoutine = MySoundComponentStartSource;
  10016.                 break;
  10017.             case kSoundComponentPlaySourceBufferSelect:
  10018.                 myRoutine = MySoundComponentPlaySourceBuffer;
  10019.                 break;
  10020.             case kSoundComponentGetInfoSelect:
  10021.                 myRoutine = MySoundComponentGetInfo;
  10022.                 break;
  10023.             case kSoundComponentSetInfoSelect:
  10024.                 myRoutine = MySoundComponentSetInfo;
  10025.                 break;
  10026.             case kSoundComponentAddSourceSelect:
  10027.             case kSoundComponentRemoveSourceSelect:
  10028.             case kSoundComponentStopSourceSelect:
  10029.             case kSoundComponentPauseSourceSelect:
  10030.             default:
  10031.                 myRoutine = kDelegateCall;                                                    /*delegate it*/
  10032.                 break;
  10033.         }
  10034.  
  10035.     return (myRoutine);
  10036. }
  10037. In all likelihood, your component is loaded into the system heap, although it might be loaded into an application heap if memory is low in the system heap. You can call the Component Manager function GetComponentInstanceA5 to determine the A5 value of the current application. If this function returns 0, your component is in the system heap; otherwise, your component is in an application’s heap. Its location might affect how you allocate memory. For example, calling the MoveHHi routine on handles in the system heap has no result. Thus, you should either call the ReserveMemSys routine before calling NewHandleSys (so that the handle is allocated as low in the system heap as possible) or else just allocate a nonrelocatable block by calling the NewPtrSys routine.
  10038. If you need to access resources that are stored in your sound component, you can use OpenComponentResFile and CloseComponentResFile. OpenComponentResFile requires the ComponentInstance parameter supplied to your routine. You should not call Resource Manager routines such as OpenResFile or CloseResFile.
  10039. sWARNING
  10040. Do not leave any resource files open when your sound component is closed. Their maps will be left in the subheap when the subheap is freed, causing the Resource Manager to crash.s
  10041. The following sections illustrate how to define some of the sound component functions.
  10042. Registering and Opening a Sound Component
  10043.  
  10044. The Component Manager sends your component the kComponentRegisterSelect selector, usually at system startup time, to allow your component to determine whether it wants to register itself with the Component Manager. Utility components should always register themselves, so that the capabilities they provide will be available when needed. Sound output device components, however, should first check to see whether any necessary hardware is available before registering themselves. If the hardware they drive isn’t available, there is no point in registering with the Component Manager.
  10045. The Component Manager sends your component the kComponentOpenSelect selector whenever the Sound Manager wants to open a connection to your component. In general, a sound output device component has only one connection made to it. A utility component, however, might have several instances, if the capabilities it provides are needed by more than one sound component chain. Your component should do as little as possible when opening up. It should allocate whatever global storage it needs to manage the connection and call SetComponentInstanceStorage so that the Component Manager can remember the location of that storage and pass it to all other component-defined routines.
  10046. As noted in the previous section, your component is probably loaded into the system heap. If so, you should also allocate any global storage in the system heap. If memory is tight, however, your component might be loaded into an application’s heap (namely, the heap of the first application that plays sound). In that case, you should allocate any global variables you need in that heap. The Sound Manager ensures that other applications will not try to play sound while the component is in this application heap.
  10047. IMPORTANT
  10048. Your component is always sent the kComponentOpenSelect component selector before it is sent the kComponentRegisterSelect selector. As a result, you should not attempt to initialize or configure any associated hardware in response to kComponentOpenSelect.s
  10049. The Sound Manager sends the kSoundComponentInitOutputDeviceSelect selector specifically to allow a sound output device component to perform any hardware-related operations. Your component should initialize the hardware to some reasonable default values, create the Apple Mixer, and allocate any other memory that might be needed. Listing 5-4 shows one way to respond to the kSoundComponentInitOutputDeviceSelect selector.
  10050. Listing 5-4    Initializing an output device
  10051.  
  10052. static pascal ComponentResult MySoundComponentInitOutputDevice 
  10053.                         (SoundComponentGlobalsPtr globals, long actions)
  10054. {
  10055. #pragma unused (actions)
  10056.     ComponentResult                                myResult;
  10057.  
  10058.     /*Make sure we got our globals.*/
  10059.     if (globals->hwGlobals == nil)
  10060.         return (notEnoughHardwareErr);
  10061.  
  10062.     /*Set up the hardware.*/
  10063.     myResult = MySetupHardware(globals);
  10064.     if (myResult != noErr)
  10065.         return (myResult);
  10066.  
  10067.     /*Create an Apple Mixer.*/
  10068.     myResult = OpenMixerSoundComponent(&globals->thisComp, 0,
  10069.                                                  &globals->sourceComponent);
  10070.  
  10071.     return (myResult);
  10072. }
  10073. The MySoundComponentInitOutputDevice function defined in Listing 5-4 simply retrieves the location of its global variables, configures the hardware by calling the MySetupHardware function, and then calls OpenMixerSoundComponent to create an instance of the Apple Mixer.
  10074. Finding and Changing Component Capabilities
  10075.  
  10076. All sound components take a stream of input data and produce a (usually different) stream of output data. The Sound Manager needs to know what operations your component can perform, so that it knows what other sound components might need to be linked together to play a particular sound on the available sound output device. It calls your component’s SoundComponentGetInfo and SoundComponentSetInfo functions to get and set information about the capabilities and current settings of your sound component.
  10077. To specify the kind of information it wants to get or set, the Sound Manager passes your component a sound component information selector. If your component does not support a particular selector, if should pass the selector to the specified sound source. If your component does support the selector, it should either return the desired information directly or alter its settings as requested.
  10078. The sound component information selectors can specify any of a large number of audio capabilities or component settings. For example, the selector siRateMultiplier is passed to get or set the current output sample rate multiplier value.
  10079. Note
  10080. The Sound Manager uses many of the sound input device information selectors defined by the Sound Input Manager for communicating with sound input devices. See “Sound Input Manager” in this book for a description of the sound input device information selectors. A complete list of all sound component information selectors is provided in “Sound Component Information Selectors” beginning on page 5-22.u
  10081. Your component’s SoundComponentGetInfo function has the following declaration:
  10082. pascal ComponentResult SoundComponentGetInfo (ComponentInstance ti, 
  10083.                                                     SoundSource sourceID, OSType selector, 
  10084.                                                     void *infoPtr);
  10085. The sound component information selector is passed in the selector parameter. The sound source is identified by the source ID passed in the sourceID parameter. The infoPtr parameter specifies the location in memory of the information returned by SoundComponentGetInfo. If the information to be returned occupies four bytes or fewer, you can simply return the information in the location pointed to by that parameter. Otherwise, you should pass back in the infoPtr parameter a pointer to a record of type SoundInfoList, which contains an integer and a handle to an array of data items. In the second case, you’ll need to allocate memory to hold the information you need to pass back. Listing 5-5 defines a component’s SoundComponentGetInfo routine. It returns information to the Sound Manager about its capabilities and current settings.
  10086. Listing 5-5    Getting sound component information
  10087.  
  10088. static pascal ComponentResult MySoundComponentGetInfo 
  10089.                             (SoundComponentGlobalsPtr globals, SoundSource sourceID, 
  10090.                                 OSType selector, void *infoPtr)
  10091. {
  10092.     HandleListPtr                            listPtr;
  10093.     short                            *sp, i;
  10094.     UnsignedFixed                            *lp;
  10095.     Handle                            h;
  10096.     HardwareGlobalsPtr                            hwGlobals = globals->hwGlobals;
  10097.     ComponentResult                            result = noErr;
  10098.  
  10099.     /*Make sure we got our global variables.*/
  10100.     if (hwGlobals == nil)
  10101.         return (notEnoughHardwareErr);
  10102.  
  10103.     switch (selector)
  10104.     {
  10105.         case siSampleSize:                                                /*return current sample size*/
  10106.             *((short *) infoPtr) = hwGlobals->sampleSize;
  10107.             break;
  10108.  
  10109.         case siSampleSizeAvailable:                                                /*return sample sizes available*/
  10110.             h = NewHandle(sizeof(short) * kSampleSizesCount);
  10111.             if (h == nil)
  10112.                 return (MemError());
  10113.  
  10114.             listPtr = (HandleListPtr) infoPtr;
  10115.             listPtr->count = 0;                                            /*num. sample sizes in handle*/
  10116.             listPtr->handle = h;                                            /*handle to be returned*/
  10117.  
  10118.             sp = (short *) *h;                                            /*store sample sizes in handle*/
  10119.  
  10120.             for (i = 0; i < kSampleSizesCount; ++i)
  10121.                 if (hwGlobals->sampleSizesActive[i])
  10122.                 {
  10123.                     listPtr->count++;
  10124.                     *sp++ = hwGlobals->sampleSizes[i];
  10125.                 }
  10126.             break;
  10127.  
  10128.         case siSampleRate:                                                /*return current sample rate*/
  10129.             *((Fixed *) infoPtr) = hwGlobals->sampleRate;
  10130.             break;
  10131.  
  10132.         case siSampleRateAvailable:                                                /*return sample rates available*/
  10133.             h = NewHandle(sizeof(UnsignedFixed) * kSampleRatesCount);
  10134.             if (h == nil)
  10135.                 return (MemError());
  10136.  
  10137.             listPtr = (HandleListPtr) infoPtr;
  10138.             listPtr->count = 0;                                            /*num. sample rates in handle*/
  10139.             listPtr->handle = h;                                            /*handle to be returned*/
  10140.  
  10141.             lp = (UnsignedFixed *) *h;
  10142.  
  10143.             /*If the hardware can support a range of sample rate values,
  10144.               the list count should be set to 0 and the minimum and maximum
  10145.               sample rate values should be stored in the handle.*/
  10146.             if (hwGlobals->supportsRateRange)
  10147.             {
  10148.                 *lp++ = hwGlobals->sampleRateMin;
  10149.                 *lp++ = hwGlobals->sampleRateMax;
  10150.             }
  10151.             
  10152.             /*If the hardware supports a limited set of sample rates, 
  10153.               the list count should be set to the number of sample rates 
  10154.               and this list of rates should be stored in the handle.*/
  10155.             else
  10156.             {
  10157.                 for (i = 0; i < kSampleRatesCount; ++i)
  10158.                     if (hwGlobals->sampleRatesActive[i])
  10159.                     {
  10160.                         listPtr->count++;
  10161.                         *lp++ = hwGlobals->sampleRates[i];
  10162.                     }
  10163.             }
  10164.             break;
  10165.  
  10166.         case siNumberChannels:                                                /*return current num. channels*/
  10167.             *((short *) infoPtr) = hwGlobals->numChannels;
  10168.             break;
  10169.  
  10170.         case siChannelAvailable:                                                /*return channels available*/
  10171.             h = NewHandle(sizeof(short) * kChannelsCount);
  10172.             if (h == nil)
  10173.                 return (MemError());
  10174.  
  10175.             listPtr = (HandleListPtr) infoPtr;
  10176.             listPtr->count = 0;                                            /*num. channels in handle*/
  10177.             listPtr->handle = h;                                            /*handle to be returned*/
  10178.  
  10179.             sp = (short *) *h;                                            /*store channels in handle*/
  10180.  
  10181.             for (i = 0; i < kChannelsCount; ++i)
  10182.                 if (hwGlobals->channelsActive[i])
  10183.                 {
  10184.                     listPtr->count++;
  10185.                     *sp++ = hwGlobals->channels[i];
  10186.                 }
  10187.             break;
  10188.  
  10189.         case siHardwareVolume:
  10190.             *((long *)infoPtr) = hwGlobals->volume;
  10191.             break;
  10192.  
  10193.         /*If you do not handle a selector, delegate it up the chain.*/
  10194.         default:
  10195.             result = SoundComponentGetInfo(globals->sourceComponent, sourceID, 
  10196.                                                 selector, infoPtr);
  10197.             break;
  10198.     }
  10199.     return (result);
  10200. }
  10201. You can define your MySoundComponentSetInfo routine in an exactly similar fashion.
  10202.  
  10203.  
  10204. Sound Components Reference
  10205.  
  10206. This section describes the constants, data structures, and routines you can use to write a sound component. It also describes the routines that your sound component should call in response to a sound component selector. See “Writing a Sound Component” on page 5-8 for information on creating a component that contains these component-defined routines.
  10207. Constants
  10208.  
  10209. This section provides details on the constants defined by the Sound Manager for use with sound components. You’ll use these constants to
  10210. n    determine the kind of information the Sound Manager wants your sound component to return to it or settings it wants your sound component to change
  10211. n    define the format of the audio data your sound component is currently producing
  10212. n    specify the action flags for the SoundComponentPlaySourceBuffer function
  10213. n    specify the format of the data your sound output device component expects to receive
  10214. Sound Component Information Selectors
  10215.  
  10216. The Sound Manager calls your sound component’s SoundComponentGetInfo and SoundComponentSetInfo functions to determine the capabilities of your component and to change those capabilities. It passes those functions a sound component information selector in the function’s selector parameter to specify the type of information it wants to get or set. The available sound component information selectors are defined by constants.
  10217. Note
  10218. Most of these selectors can be passed to both SoundComponentGetInfo and SoundComponentSetInfo. Some of them, however, can be sent to only one or the other.u
  10219. #define siChannelAvailable                                            'chav'            /*number of channels available*/
  10220. #define siCompressionAvailable                                            'cmav'            /*compression types available*/
  10221. #define siCompressionFactor                                            'cmfa'            /*current compression factor*/
  10222. #define siCompressionType                                            'comp'            /*current compression type*/
  10223. #define siHardwareMute                                            'hmut'            /*current hardware mute state*/
  10224. #define siHardwareVolume                                            'hvol'            /*current hardware volume*/
  10225. #define siHardwareVolumeSteps                                            'hstp'            /*number of hardware volume steps*/
  10226. #define siHeadphoneMute                                            'pmut'            /*current headphone mute state*/
  10227. #define siHeadphoneVolume                                            'pvol'            /*current headphone volume*/
  10228. #define siHeadphoneVolumeSteps                                            'hdst'            /*num. of headphone volume steps*/
  10229. #define siNumberChannels                                            'chan'            /*current number of channels*/
  10230. #define siQuality                                            'qual'            /*current quality*/
  10231. #define siRateMultiplier                                            'rmul'            /*current rate multiplier*/
  10232. #define siSampleRate                                            'srat'            /*current sample rate*/
  10233. #define siSampleRateAvailable                                            'srav'            /*sample rates available*/
  10234. #define siSampleSize                                            'ssiz'            /*current sample size*/
  10235. #define siSampleSizeAvailable                                            'ssav'            /*sample sizes available*/
  10236. #define siSpeakerMute                                            'smut'            /*current speaker mute*/
  10237. #define siSpeakerVolume                                            'svol'            /*current speaker volume*/
  10238. #define siVolume                                            'volu'            /*current volume setting*/
  10239. Constant descriptions
  10240. siChannelAvailable
  10241. Get the maximum number of channels this sound component can manage, as well as the channels themselves. The infoPtr parameter points to a record of type SoundInfoList, which contains an integer (the number of available channels) and a handle to an array of integers (which represent the channel numbers themselves).
  10242. siCompressionAvailable
  10243. Get the number and list of compression types this sound component can manage. The infoPtr parameter points to a record of type SoundInfoList, which contains the number of compression types, followed by a handle that references a list of compression types, each of type OSType.
  10244. siCompressionFactor
  10245. Get information about the current compression type. The infoData parameter points to a compression information record (see page 5-32).
  10246. siCompressionType
  10247. Get or set the current compression type. The infoPtr parameter points to a buffer of type OSType, which is the compression type.
  10248. siHardwareMute
  10249. Get or set the current mute state of the audio hardware. A value of 0 indicates that the hardware is not muted, and a value of 1 indicates that the hardware is muted. Not all sound components need to support this selector; it’s intended for sound output device components whose associated hardware can be muted.
  10250. siHardwareVolume
  10251. Get or set the current volume level of all sounds produced on the sound output device. The infoPtr parameter points to a long integer, where the high-order word represents the right volume level and the low-order word represents the left volume level. A volume level is specified by an unsigned 16-bit number: 0x0000 represents silence and 0x0100 represents full volume. (You can use the constant kFullVolume for full volume.) You can specify values larger than 0x0100 to overdrive the volume, although doing so might result in clipping. This selector applies to the volume of the output device, whereas the siVolume selector applies to the volume of a specific sound channel and its component chain. If a sound output device supports more than one output port (for example, both headphones and speakers), the siHardwareVolume selector applies to all those ports.
  10252. siHardwareVolumeSteps
  10253. Get the number of audible volume levels supported by the audio hardware. If the device supports a range of volume levels (for example, 0x000 to 0x1000), you should return only the number of levels that are audible. The Sound Manager uses this information to handle the volume slider in the Alert Sounds control panel.
  10254. siHeadphoneMute
  10255. Get or set the current mute state of the headphone. A value of 0 indicates that the headphone is not muted, and a value of 1 indicates that the headphone is muted. Not all sound components need to support this selector; it’s intended for sound output device components whose associated headphone can be muted.
  10256. siHeadphoneVolume
  10257. Get or set the current volume level of all sounds produced on the headphone. The infoPtr parameter points to a long integer, where the high-order word represents the right volume level and the low-order word represents the left volume level. A volume level is specified by an unsigned 16-bit number: 0x0000 represents silence and 0x0100 represents full volume. (You can use the constant kFullVolume for full volume.) You can specify values larger than 0x0100 to overdrive the volume, although doing so might result in clipping. This selector applies to the volume of the headphones.
  10258. siHeadphoneVolumeSteps
  10259. Get the number of audible volume levels supported by the headphones. If the headphones support a range of volume levels (for example, 0x000 to 0x1000), you should return only the number of levels that are audible.
  10260. siNumberChannels
  10261. Get or set the current number of audio channels currently being managed by the sound component. The infoPtr parameter points to an integer, which is the number of channels. For example, for stereo sounds, this integer should be 2.
  10262. siQuality    Get or set the current quality setting for the sound component. The infoPtr parameter points to a 32-bit value, which typically determines how much processing should be applied to the audio data stream.
  10263. siRateMultiplier
  10264. Get or set the current rate multiplier for the sound component. The infoPtr parameter points to a buffer of type UnsignedFixed, which is the multiplier to be applied to the playback rate of the sound, independent of the base sample rate of the sound. For example, if the current rate multiplier is 2.0, the sound is played back at twice the speed specified in the sampleRate field of the sound component data record.
  10265. siSampleRate    Get or set the current sample rate of the data being output by the sound component. The infoPtr parameter points to a buffer of type UnsignedFixed, which is the sample rate.
  10266. siSampleRateAvailable
  10267. Get the range of sample rates this sound component can handle. The infoPtr parameter points to a record of type SoundInfoList, which is the number of sample rates the component supports, followed by a handle to a list of sample rates, each of type UnsignedFixed. The sample rates can be in the range 0 to 65535.65535. If the number of sample rates is 0, then the first two sample rates in the list define the lowest and highest values in a continuous range of sample rates.
  10268. siSampleSize    Get or set the current sample size of the audio data being output by the sound component. The infoPtr parameter points to an integer, which is the sample size in bits.
  10269. siSampleSizeAvailable
  10270. Get the range of sample sizes this sound component can handle. The infoPtr parameter points to a record of type SoundInfoList, which is the number of sample sizes the sound component supports, followed by a handle. The handle references a  list of sample sizes, each of type Integer. Sample sizes are specified in bits.
  10271. siSpeakerMute
  10272. Get or set the current mute state of the speakers. A value of 0 indicates that the speakers are not muted, and a value of 1 indicates that the speakers are muted. Not all sound components need to support this selector; it’s intended for sound output device components whose associated speakers can be muted.
  10273. siSpeakerVolume
  10274. Get or set the current volume level of all sounds produced on the speakers. The infoPtr parameter points to a long integer, where the high-order word represents the right volume level and the low-order word represents the left volume level. A volume level is specified by an unsigned 16-bit number: 0x0000 represents silence and 0x0100 represents full volume. (You can use the constant kFullVolume for full volume.) You can specify values larger than 0x0100 to overdrive the volume, although doing so might result in clipping. This selector applies to the volume of the speakers.
  10275. siVolume    Get or set the current volume level of the sound component. The infoPtr parameter points to a long integer, where the high-order word represents the right volume level and the low-order word represents the left volume level. A volume level is specified by an unsigned 16-bit number: 0x0000 represents silence and 0x0100 represents full volume. (You can use the constant kFullVolume for full volume.) You can specify values larger than 0x0100 to overdrive the volume, although doing so might result in clipping. This selector applies to the volume of a specific sound channel and its component chain, while the siHardwareVolume selector applies to the volume of the output device.
  10276. Audio Data Types
  10277.  
  10278. You can use the following constants to define the format of the audio data your sound component is currently producing. You can also define additional data types to denote your own compression schemes. You pass these constants in the format field of a sound component data record.
  10279. #define kOffsetBinary                                        'raw '
  10280. #define kTwosComplement                                        'twos'
  10281. #define kMACE3Compression                                        'MAC3'
  10282. #define kMACE6Compression                                        'MAC6'
  10283. Constant descriptions
  10284. kOffsetBinary    The data is noncompressed samples in offset binary format (that is, values range from 0 to 255).
  10285. kTwosComplement
  10286. The data is noncompressed samples in two’s complement format (that is, values range from –128 to 128).
  10287. kMACE3Compression
  10288. The data is compressed using MACE 3:1 compression.
  10289. kMACE6Compression
  10290. The data is compressed using MACE 6:1 compression.
  10291. Sound Component Features Flags
  10292.  
  10293. You can use the following constants to define features of your sound component. You use some combination of these constants to set bits in the componentFlags field of a component description record, which is contained in a 'thng' resource. These bits represent the kind of data your component can receive as input, the kind of data your component can produce as output, the operations your component can perform, and the performance of your component.
  10294. #define k8BitRawIn                                            (1 << 0)                /*data flags*/
  10295. #define k8BitTwosIn                                            (1 << 1)
  10296. #define k16BitIn                                            (1 << 2)
  10297. #define kStereoIn                                            (1 << 3)
  10298. #define k8BitRawOut                                            (1 << 8)
  10299. #define k8BitTwosOut                                            (1 << 9)
  10300. #define k16BitOut                                            (1 << 10)
  10301. #define kStereoOut                                            (1 << 11)
  10302. #define kReverse                                            (1 << 16)                /*action flags*/
  10303. #define kRateConvert                                            (1 << 17)
  10304. #define kCreateSoundSource                                            (1 << 18)
  10305. #define kHighQuality                                            (1 << 22)                /*performance flags*/
  10306. #define kRealTime                                            (1 << 23)
  10307. Constant descriptions
  10308. k8BitRawIn    The component can accept 8 bit offset binary data as input.
  10309. k8BitTwosIn    The component can accept 8 bit two’s complement data as input.
  10310. k16BitIn    The component can accept 16 bit data as input. 16 bit data is always in two’s complement format.
  10311. kStereoIn    The component can accept stereo data as input.
  10312. k8BitRawOut    The component can produce 8 bit offset binary data as output.
  10313. k8BitTwosOut    The component can produce 8 bit two’s complement data as output.
  10314. k16BitOut    The component can produce 16 bit data as output. 16 bit data is always in two’s complement format.
  10315. kStereoOut    The component can produce stereo data as output.
  10316. kReverse    The component can accept reversed audio data. 
  10317. kRateConvert    The component can convert sample rates.
  10318. kCreateSoundSource
  10319. The component can create sound sources.
  10320. kHighQuality    The component can produce high quality output.
  10321. kRealTime    The component can operate in real time.
  10322. Action Flags
  10323.  
  10324. You can use constants to specify the action flags in the actions parameter of the SoundComponentPlaySourceBuffer function. See page 5-49 for information about this function.
  10325. #define kSourcePaused                                            (1 << 0)
  10326. #define kPassThrough                                            (1 << 16)
  10327. #define kNoSoundComponentChain                                            (1 << 17)
  10328. Constant descriptions
  10329. kSourcePaused    If this bit is set, the component chain is configured to play the specified sound but the playback is initially paused. In this case, your SoundComponentStartSource function must be called to begin playback. If this bit is clear, the playback begins immediately once the component chain is set up and configured.
  10330. kPassThrough    If this bit is set, the Sound Manager passes all data through to the sound output device component unmodified. A sound output device component that can handle any sample rate and sound format described in a sound parameter block should set this bit.
  10331. kNoSoundComponentChain
  10332. If this bit is set, the Sound Manager does not construct a component chain for processing the sound data.
  10333. Data Format Flags
  10334.  
  10335. You can use constants to set or clear flag bits in the outputFlags parameter passed to the OpenMixerSoundComponent routine. These flags specify the format of the data your sound output device component expects to receive. See page 5-33 for information about the OpenMixerSoundComponent function.
  10336. IMPORTANT
  10337. Most of these flags are ignored unless the kNoMixing flag is set, because a sound output device component cannot perform data modifications such as sample rate conversion or sample size conversion unless it is also able to mix sound sources.s
  10338. #define kNoMixing                                            (1 << 0)                /*don't mix sources*/
  10339. #define kNoSampleRateConversion                                            (1 << 1)                /*don't convert sample rate*/
  10340. #define kNoSampleSizeConversion                                            (1 << 2)                /*don't convert sample size*/
  10341. #define kNoSampleFormatConversion                                                        \
  10342.                                             (1 << 3)                /*don't convert sample format*/
  10343. #define kNoChannelConversion                                            (1 << 4)                /*don't convert stereo/mono*/
  10344. #define kNoDecompression                                            (1 << 5)                /*don't decompress*/
  10345. #define kNoVolumeConversion                                            (1 << 6)                /*don't apply volume*/
  10346. #define kNoRealtimeProcessing                                            (1 << 7)                /*don't run at interrupt time*/
  10347. Constant descriptions
  10348. kNoMixing    If this bit is set, the Apple Mixer does not mix audio data sources.
  10349. kNoSampleRateConversion
  10350. If this bit is set, the sound component chain does not perform sample rate conversion (for example, converting 11 kHz data to 22 kHz data).
  10351. kNoSampleSizeConversion
  10352. If this bit is set, the sound component chain does not perform sample size conversion (for example, converting 8-bit data to 16-bit data).
  10353. kNoSampleFormatConversion
  10354. If this bit is set, the sound component chain does not convert between sample formats (for example, converting from two’s complement data to offset binary data). Most sound output devices on Macintosh computers accept only 8-bit offset binary data, which is therefore the default type of data produced by the Apple Mixer. If your output device can handle either offset binary or two’s complement data, you should set this flag. Note that 16-bit data is always in two’s complement format.
  10355. kNoChannelConversion
  10356. If this bit is set, the sound component chain does not convert channels (for example, converting monophonic channels to stereo or stereo channels to monophonic).
  10357. kNoDecompression
  10358. If this bit is set, the sound component chain does not decompress audio data. If your output device can decompress data, you should set this flag.
  10359. kNoVolumeConversion
  10360. If this bit is set, the sound component chain does not convert volumes.
  10361. kNoRealtimeProcessing
  10362. If this bit is set, the sound component chain does not do any processing at interrupt time.
  10363. Data Structures
  10364.  
  10365. This section describes the data structures you need to use when writing a sound component.
  10366. Sound Component Data Records
  10367.  
  10368. The flow of data from one sound component to another is managed using a sound component data record. This record indicates to other sound components the format of the data that a particular component is generating, together with the location and length of the buffer containing that data. This allows other sound components to access data from that component as needed. A sound component data record is defined by the SoundComponentData data type.
  10369. typedef struct {
  10370.     long                    flags;                            /*sound component flags*/
  10371.     OSType                    format;                            /*data format*/
  10372.     short                    numChannels;                            /*number of channels in data*/
  10373.     short                    sampleSize;                            /*size of a sample*/
  10374.     UnsignedFixed                    sampleRate;                            /*sample rate*/
  10375.     long                    sampleCount;                            /*number of samples in buffer*/
  10376.     Byte                    *buffer;                            /*location of data*/
  10377.     long                    reserved;                            /*reserved*/
  10378. } SoundComponentData, *SoundComponentDataPtr;
  10379. Field descriptions
  10380. flags    A set of bit flags whose meanings are specific to a particular sound component.
  10381. format    The format of the data a sound component is producing. The following formats are defined by Apple:
  10382.                     #define kOffsetBinary                                        'raw '
  10383.                     #define kTwosComplement                                        'twos'
  10384.                     #define kMACE3Compression                                        'MAC3'
  10385.                     #define kMACE6Compression                                        'MAC6'
  10386.     See “Audio Data Types” on page 5-26 for a description of these formats. You can define additional format types, which are currently assumed to be the types of proprietary compression algorithms.
  10387. numChannels    The number of channels of sound in the output data stream. If this field contains the value 1, the data is monophonic. If this field contains 2, the data is stereophonic. Stereo data is stored as interleaved samples, in a left-to-right ordering.
  10388. sampleSize    The size, in bits, of each sample in the output data stream. Typically this field contains the values 8 or 16. For compressed sound data, this field indicates the size of the samples after the data has been expanded.
  10389. sampleRate    The sample rate for the audio data. The sample rate is expressed as an unsigned, fixed-point number in the range 0 to 65536.0 samples per second.
  10390. sampleCount    The number of samples in the buffer pointed to by the buffer field. For compressed sounds, this field indicates the number of compressed samples in the sound, not the size of the buffer.
  10391. buffer    The location of the buffer that contains the sound data. 
  10392. reserved    Reserved for future use. You should set this field to 0.
  10393. Sound Parameter Blocks
  10394.  
  10395. The Sound Manager passes a component’s SoundComponentPlaySourceBuffer function a sound parameter block that describes the source data to be modified or sent to a sound output device. A sound parameter block is defined by the SoundParamBlock data type.
  10396. struct SoundParamBlock {
  10397.     long                            recordSize;                    /*size of this record in bytes*/
  10398.     SoundComponentData                            desc;                    /*description of sound buffer*/
  10399.     Fixed                            rateMultiplier;                    /*rate multiplier*/
  10400.     short                            leftVolume;                    /*volume on left channel*/
  10401.     short                            rightVolume;                    /*volume on right channel*/
  10402.     long                            quality;                    /*quality*/
  10403.     ComponentInstance                            filter;                    /*filter*/
  10404.     SoundParamProcPtr                            moreRtn;                    /*routine to call to get more data*/
  10405.     SoundParamProcPtr                            completionRtn;                    /*buffer complete routine*/
  10406.     long                            refCon;                    /*user refcon*/
  10407.     short                            result;                    /*result*/
  10408. };
  10409. typedef struct SoundParamBlock SoundParamBlock;
  10410. typedef SoundParamBlock *SoundParamBlockPtr;
  10411. Field descriptions
  10412. recordSize    The length, in bytes, of the sound parameter block.
  10413. desc    A sound component data record that describes the format, size, and location of the sound data. See “Sound Component Data Records” on page 5-29 for a description of the sound component data record.
  10414. rateMultiplier
  10415. A multiplier to be applied to the playback rate of the sound. This field contains an unsigned fixed-point number. If, for example, this field has the value 2.0, the sound is played back at twice the rate specified in the sampleRate field of the sound component data record contained in the desc field.
  10416. leftVolume    The playback volume for the left channel. You specify a volume with 16-bit value, where 0 (hexadecimal 0x0000) represents no volume and 256 (hexadecimal 0x0100) represents full volume. You can overdrive a channel’s volume by passing volume levels greater than 0x0100.
  10417. rightVolume    The playback volume for the right channel. You specify a volume with 16-bit value, where 0 (hexadecimal 0x0000) represents no volume and 256 (hexadecimal 0x0100) represents full volume. You can overdrive a channel’s volume by passing volume levels greater than 0x0100.
  10418. quality    The level of quality for the sound. This value usually determines how much processing should be applied during audio data processing (such as rate conversion and decompression) to increase the output quality of the sound.
  10419. filter    Reserved for future use. You should set this field to nil.
  10420. moreRtn    A pointer to a callback routine that is called to retrieve another buffer of audio data. This field is used internally by the Sound Manager.
  10421. completionRtn    A pointer to a callback routine that is called when the sound has finished playing. This field is used internally by the Sound Manager.
  10422. refCon    A value that is to be passed to the callback routines specified in the moreRtn and completionRtn fields. You can use this field to pass information (for example, the address of a structure) to a callback routine.
  10423. result    The status of the sound that is playing. The value 1 indicates that the sound is currently playing. The value 0 indicates that the sound has finished playing. Any negative value indicates that some error has occurred.
  10424. Sound Information Lists
  10425.  
  10426. The SoundComponentGetInfo and SoundComponentSetInfo functions access information about a sound component using a sound information list, which is defined by the SoundInfoList data type.
  10427. typedef struct {
  10428.     short                    count;
  10429.     Handle                    handle;
  10430. } SoundInfoList, *SoundInfoListPtr;
  10431. Field descriptions
  10432. count    The number of elements in the array referenced by the handle field.
  10433. handle    A handle to an array of data elements. The type of these data elements depends on the kind of information requested, which is determined by the selector parameter passed to SoundComponentGetInfo or SoundComponentSetInfo. See “Sound Component Information Selectors” beginning on page 5-22 for information about the available information selectors.
  10434. Compression Information Records
  10435.  
  10436. When the Sound Manager calls your SoundComponentGetInfo routine with the siCompressionFactor selector, you need to return a pointer to a compression information record, which is defined by the CompressionInfo data type.
  10437. typedef struct {
  10438.     long                    recordSize;
  10439.     OSType                    format;
  10440.     short                    compressionID;
  10441.     short                    samplesPerPacket;
  10442.     short                    bytesPerPacket;
  10443.     short                    bytesPerFrame;
  10444.     short                    bytesPerSample;
  10445.     short                    futureUse1;
  10446. } CompressionInfo, *CompressionInfoPtr, **CompressionInfoHandle;
  10447. Field descriptions
  10448. recordSize    The size of this compression information record.
  10449. format    The compression format.
  10450. compressionID    The compression ID.
  10451. samplesPerPacket
  10452. The number of samples in each packet.
  10453. bytesPerPacket
  10454. The number of bytes in each packet.
  10455. bytesPerFrame
  10456. The number of bytes in each frame.
  10457. bytesPerSample
  10458. The number of bytes in each sample.
  10459. futureUse1    Reserved for use by Apple Computer, Inc. You should set this field to 0.
  10460. Sound Manager Utilities
  10461.  
  10462. This section describes several utility routines provided by the Sound Manager that are intended for use only by sound components. You can use these routines to
  10463. n    open and close the Apple Mixer component
  10464. n    save and restore a user’s preference settings for a sound component
  10465. Note
  10466. For a description of the routines that a sound component must implement, see “Sound Component-Defined Routines” on page 5-36.u
  10467. Opening and Closing the Apple Mixer Component
  10468.  
  10469. A sound output device component needs to open and close one or more instances of the Apple Mixer component.
  10470. OpenMixerSoundComponent
  10471.  
  10472. A sound output device component can use the OpenMixerSoundComponent function to open and connect itself to the Apple Mixer component.
  10473. pascal OSErr OpenMixerSoundComponent 
  10474.                                 (SoundComponentDataPtr outputDescription, 
  10475.                                 long outputFlags, 
  10476.                                 ComponentInstance *mixerComponent);
  10477. outputDescription
  10478. A description of the data format your sound output device is expecting to receive.
  10479. outputFlags
  10480. A set of 32 bit flags that provide additional information about the data format your output device is expecting to receive. See “Data Format Flags” beginning on page 5-28 for a description of the constants you can use to select bits in this parameter.
  10481. mixerComponent
  10482. The component instance of the Apple Mixer component. You need this instance to call the SoundComponentGetSourceData and CloseMixerSoundComponent functions.
  10483. DESCRIPTION
  10484. The OpenMixerSoundComponent function opens the standard Apple Mixer component and creates a connection between your sound output device component and the Apple Mixer. If your output device can perform specific operations on the stream of audio data, such as channel mixing and rate conversion, it should call OpenMixerSoundComponent as many times as are necessary to create a unique component chain for each sound source. If, on the other hand, your output device does not perform channel mixing, it should call OpenMixerSoundComponent only once, from its SoundComponentInitOutputDevice function. This opens a single instance of the Apple Mixer component, which in turn manages all the available sound sources.
  10485. Your component specifies the format of the data it can handle by filling in a sound component data record and passing its address in the outputDescription parameter. The sound component data record specifies the data format as well as the sample rate and sample size expected by the output device component. If these specifications are sufficient to determine the kind of data your component can handle, you should pass the value 0 in the outputFlags parameter. Otherwise, you can set flags in the outputFlags parameter to select certain kinds of input data. For example, you can set the kNoChannelConversion flag to prevent the component chain from converting monophonic sound to stereo sound, or stereo sound to monophonic sound. See “Data Format Flags” beginning on page 5-28 for a description of the constants you can use to select bits in the outputFlags parameter.
  10486. SPECIAL CONSIDERATIONS
  10487. The OpenMixerSoundComponent function is available only in versions 3.0 and later of the Sound Manager. It should be called only by sound output device components.
  10488. CloseMixerSoundComponent
  10489.  
  10490. A sound output device component can use the CloseMixerSoundComponent function to close the Apple Mixer.
  10491. pascal OSErr CloseMixerSoundComponent (ComponentInstance ci);
  10492. ci    The component instance of the Apple Mixer component.
  10493. DESCRIPTION
  10494. The CloseMixerSoundComponent function closes the Apple Mixer component instance specified by the ci parameter. Your output device component should call this function when it is being closed.
  10495. SPECIAL CONSIDERATIONS
  10496. The CloseMixerSoundComponent function is available only in versions 3.0 and later of the Sound Manager. It should be called only by sound output device components.
  10497. RESULT CODESnoErr    0    No error    
  10498. invalidComponentID    –3000    Invalid component ID    
  10499.  
  10500. Saving and Restoring Sound Component Preferences
  10501.  
  10502. A sound component can use the SetSoundPreference and GetSoundPreference functions to save and restore a user’s preference settings.
  10503. SetSoundPreference
  10504.  
  10505. A sound component can use the SetSoundPreference function to have the Sound Manager store a block of preferences data in a resource file. You’re most likely to use this function in a sound output device component, although other types of sound components can use it also.
  10506. pascal OSErr SetSoundPreference (OSType type, Str255 name, 
  10507.                                                 Handle settings);
  10508. type    The resource type to be used to create the preferences resource.
  10509. name    The resource name to be used to create the preferences resource.
  10510. settings    A handle to the data to be stored in the preferences resource.
  10511. DESCRIPTION
  10512. The SetSoundPreference function causes the Sound Manager to attempt to create a new resource that contains preferences data for your sound component. You can use this function to maintain a structure of any format across subsequent startups of the machine. You’ll retrieve the preferences data by calling the GetSoundPreference function. The data is stored in a resource with the specified type and name in a resource file in the Preferences folder in the System Folder. In general, the resource type and name should be the same as the sound component subtype and name.
  10513. The settings parameter is a handle to the preferences data you want to store. It is the responsibility of your component to allocate and initialize the block of data referenced by that handle. The Sound Manager copies the handle’s data into a resource in the appropriate location. Your sound component should dispose of the handle when SetSoundPreference returns.
  10514. The format of the block of preferences data referenced by the settings parameter is defined by your sound component. It is recommended that you include a field specifying the version of the data format; this allows you to modify the format of the block of data while remaining compatible with previous formats you might have defined.
  10515. SPECIAL CONSIDERATIONS
  10516. The SetSoundPreference function is available only in versions 3.0 and later of the Sound Manager.
  10517. GetSoundPreference
  10518.  
  10519. A sound component can use the GetSoundPreference function to have the Sound Manager read a block of preferences data from a resource file. You’ll use it to retrieve a block of preferences data you previously saved by calling SetSoundPreference.
  10520. pascal OSErr GetSoundPreference (OSType type, Str255 name, 
  10521.                                                 Handle settings);
  10522. type    The resource type of the preferences resource.
  10523. name    The resource name of the preferences resource.
  10524. settings    A handle to the data in the preferences resource.
  10525. DESCRIPTION
  10526. The GetSoundPreference function retrieves the block of preferences data you previously stored in a resource by calling the SetSoundPreference function. It is the responsibility of your component to allocate the block of data referenced by the settings handle. The Sound Manager resizes the handle (if necessary) and fills it with data from the resource with the specified type and name. Your sound component should dispose of the handle once it’s finished reading the data from it. You can determine the size of the handle returned by the Sound Manager by calling the Memory Manager’s GetHandleSize function.
  10527. SPECIAL CONSIDERATIONS
  10528. The GetSoundPreference function is available only in versions 3.0 and later of the Sound Manager.
  10529. Sound Component-Defined Routines
  10530.  
  10531. This section describes the routines you need to define in order to write a sound component. You need to write routines to
  10532. n    load, configure, and unload your sound component
  10533. n    add and remove audio sources
  10534. n    read and set component settings
  10535. n    control and process audio data
  10536. Some of these routines are optional for some types of sound components. All routines return result codes. If they succeed, they should return noErr. To simplify dispatching, the Component Manager requires these routines to return a value of type ComponentResult.
  10537. See “Writing a Sound Component” beginning on page 5-8 for a description of how you call these routines from within a sound component. See “Sound Manager Utilities” beginning on page 5-33 for a description of some Sound Manager utility routines you can use in a sound component.
  10538. Managing Sound Components
  10539.  
  10540. To write a sound component, you might need to define routines that manage the loading, configuration, and unloading of your sound component:
  10541. n    SoundComponentInitOutputDevice
  10542. n    SoundComponentSetSource
  10543. n    SoundComponentGetSource
  10544. n    SoundComponentGetSourceData
  10545. n    SoundComponentSetOutput
  10546. After the Sound Manager opens your sound component, it attempts to add your sound component to a sound component chain. Thereafter, the Sound Manager calls your component’s SoundComponentInitOutputDevice function to give you an opportunity to set default values for any associated hardware and to perform any hardware-specific operations.
  10547. SoundComponentInitOutputDevice
  10548.  
  10549. A sound output device component must implement the SoundComponentInitOutputDevice function. The Sound Manager calls this function to allow a sound output device component to configure any associated hardware devices.
  10550. pascal ComponentResult SoundComponentInitOutputDevice 
  10551.                                     (ComponentInstance ti, long actions);
  10552. ti    A component instance that identifies your sound component.
  10553. actions    A set of flags. This parameter is currently unused.
  10554. DESCRIPTION
  10555. Your SoundComponentInitOutputDevice function is called by the Sound Manager at noninterrupt time to allow your sound output device component to perform any hardware-specific initialization. You should perform any necessary initialization that was not already performed in your OpenComponent function. Note that your OpenComponent function cannot assume that the appropriate hardware is available. As a result, the Sound Manager calls your SoundComponentInitOutputDevice function when it is safe to communicate with your audio hardware. You can call the OpenMixerSoundComponent function to create a single sound component chain.
  10556. SPECIAL CONSIDERATIONS
  10557. Your SoundComponentInitOutputDevice function is always called at noninterrupt time. All other component-defined routines might be called at interrupt time. Accordingly, your SoundComponentInitOutputDevice function should handle any remaining memory allocation needed by your component and it should lock down any relocatable blocks your component will access.
  10558. RESULT CODES
  10559. Your SoundComponentInitOutputDevice function should return noErr if successful or an appropriate result code otherwise.
  10560. SEE ALSO
  10561. See Listing 5-4 on page 5-17 for a sample SoundComponentInitOutputDevice function.
  10562. SoundComponentSetSource
  10563.  
  10564. A sound component can implement the SoundComponentSetSource function. The Sound Manager calls this function to identify your component’s source component.
  10565. pascal ComponentResult SoundComponentSetSource 
  10566.                                     (ComponentInstance ti, 
  10567.                                         SoundSource sourceID, 
  10568.                                         ComponentInstance source);
  10569. ti    A component instance that identifies your sound component.
  10570. sourceID    A source ID for the source component chain created by the Apple Mixer.
  10571. source    A component instance that identifies your source component.
  10572. DESCRIPTION
  10573. Your SoundComponentSetSource function is called by the Sound Manager to identify to your sound component the sound component that is its source. The source component is identified by the source parameter. Your component uses that information when it needs to obtain more data from its source (usually, by calling its SoundComponentGetSourceData function).
  10574. Because a sound output device component is always connected directly to one or more instances of the Apple Mixer, the SoundComponentSetSource function needs to be implemented only by utility components (that is, components that perform modifications on sound data). Utility components are linked together into a chain of sound components, each link of which has only one input source. As a result, a utility component can usually ignore the sourceID parameter passed to it.
  10575. RESULT CODES
  10576. Your SoundComponentSetSource function should return noErr if successful or an appropriate result code otherwise.
  10577. SoundComponentGetSource
  10578.  
  10579. A sound component can implement the SoundComponentGetSource function. The Sound Manager calls this function to determine your component’s source component.
  10580. pascal ComponentResult SoundComponentGetSource 
  10581.                                     (ComponentInstance ti, 
  10582.                                         SoundSource sourceID, 
  10583.                                         ComponentInstance *source);
  10584. ti    A component instance that identifies your sound component.
  10585. sourceID    A source ID for the source component chain created by the Apple Mixer.
  10586. source    A component instance that identifies your source component.
  10587. DESCRIPTION
  10588. Your SoundComponentGetSource function is called by the Sound Manager to retrieve your component’s source component instance. Your component should return, in the source parameter, the component instance of your component’s source. This should be the source component instance your component was passed when the Sound Manager called your SoundComponentSetSource function.
  10589. In general, all sound components have sources, except for the source at the beginning of the source component chain. In the unlikely event that your component does not have a source, you should return nil in the source parameter. A sound output device component is always connected directly to an instance of the Apple Mixer. Accordingly, a sound output device component should return a component instance of the Apple Mixer in the source parameter and a source ID in the sourceID parameter. A utility component can ignore the sourceID parameter.
  10590. RESULT CODES
  10591. Your SoundComponentGetSource function should return noErr if successful or an appropriate result code otherwise.
  10592. SoundComponentGetSourceData
  10593.  
  10594. A utility component must implement the SoundComponentGetSourceData function. A sound output device component calls this function on its source component when it needs more data.
  10595. pascal ComponentResult SoundComponentGetSourceData 
  10596.                                     (ComponentInstance ti, 
  10597.                                         SoundComponentDataPtr *sourceData);
  10598. ti    A component instance that identifies your sound component.
  10599. sourceData
  10600. On output, a pointer to a sound component data record that specifies the type and location of the data your component has processed.
  10601. DESCRIPTION
  10602. Your SoundComponentGetSourceData function is called when the sound component immediately following your sound component in the sound component chain needs more data. Your function should generate a new block of audio data, fill out a sound component data record describing the format and location of that data, and then return the address of that record in the sourceData parameter.
  10603. Your SoundComponentGetSourceData function might itself need to get more data from its source component. To do this, call through to the source component’s SoundComponentGetSourceData function. If your component cannot generate any more data, it should set the sampleCount field of the sound component data record to 0 and return noErr.
  10604. IMPORTANT
  10605. Sound output device components do not need to implement this function, but all utility components must implement it.s
  10606. RESULT CODES
  10607. Your SoundComponentGetSourceData function should return noErr if successful or an appropriate result code otherwise.
  10608. SoundComponentSetOutput
  10609.  
  10610. A sound output device component can call the SoundComponentSetOutput function of the Apple Mixer to indicate the type of data it expects to receive.
  10611. pascal ComponentResult SoundComponentSetOutput 
  10612.                                     (ComponentInstance ti, 
  10613.                                         SoundComponentDataPtr requested, 
  10614.                                         SoundComponentDataPtr *actual);
  10615. ti    A component instance that identifies your sound component.
  10616. requested
  10617. A pointer to a sound component data record that specifies the type of the data your component expects to receive.
  10618. actual
  10619. This parameter is currently unused.
  10620. DESCRIPTION
  10621. The Apple Mixer’s SoundComponentSetOutput function can be called by a sound output device component to specify the kind of audio data the output device component wants to receive. The Apple Mixer uses that information to determine the type of sound component chain it needs to construct in order to deliver that kind of audio data to your sound output device component. For example, if your sound output device is able to accept 16-bit samples, the Sound Manager doesn’t need to convert 16-bit audio data into 8-bit data.
  10622. The following lines of code illustrate how the sound output device component for the Apple Sound Chip might call Apple Mixer’s SoundComponentSetOutput function:
  10623. myDataRec.flags = 0;                                                /*ignored here*/
  10624. myDataRec.format = kOffsetBinary;                                                /*ASC needs offset binary*/
  10625. myDataRec.sampleRate = rate22khz;                                                /*ASC needs 22 kHz samples*/
  10626. myDataRec.sampleSize = 8;                                                /*ASC needs 8-bit data*/
  10627. myDataRec.numChannels = 2;                                                /*ASC can do stereo*/
  10628. myDataRec.sampleCount = 1024;                                                /*ASC uses a 1K FIFO*/
  10629. myErr = SoundComponentSetOutput(mySource, &myDataRec, &myActual);
  10630. In general, however, a sound output device component shouldn’t need to call the Apple Mixer’s SoundComponentSetOutput function. Instead, it can indicate the type of data it expects to receive when it calls the OpenMixerSoundComponent function. The SoundComponentSetOutput function is intended for sophisticated sound output device components that might want to reinitialize the Apple Mixer.
  10631. IMPORTANT
  10632. Only the Apple Mixer component needs to implement this function.s
  10633. RESULT CODES
  10634. The Apple Mixer’s SoundComponentSetOutput function returns noErr if successful or an appropriate result code otherwise.
  10635. Creating and Removing Audio Sources
  10636.  
  10637. To write a sound output device component, you might need to define two routines that create and remove audio sources:
  10638. n    SoundComponentAddSource
  10639. n    SoundComponentRemoveSource
  10640. Your component needs to contain these functions only if, like the Apple Mixer, it can mix two or more audio channels into a single output stream. Sound components that operate on a single input stream only do not need to include these functions.
  10641. SoundComponentAddSource
  10642.  
  10643. A sound output device component that can mix multiple channel of audio data must implement the SoundComponentAddSource function to add a new sound source.
  10644. pascal ComponentResult SoundComponentAddSource 
  10645.                         (ComponentInstance ti, SoundSource *sourceID);
  10646. ti    A component instance that identifies your sound component.
  10647. sourceID    On exit, a source ID for the newly created source component chain.
  10648. DESCRIPTION
  10649. The SoundComponentAddSource function is called by the Sound Manager to create a new sound source. If your sound output device component can mix multiple channels of sound, it needs to define this function. Your SoundComponentAddSource function should call the Sound Manager function OpenMixerSoundComponent to create an new instance of the Apple Mixer component. The Apple Mixer component then creates a sound component chain capable of generating the type of data your sound output device component wants to receive.
  10650. The Apple Mixer also assigns a unique 4-byte source ID that identifies the new sound source and component chain. You can retrieve that source ID by calling the Apple Mixer’s SoundComponentAddSource function. Your SoundComponentAddSource function should then pass that source ID back to the Sound Manager in the sourceID parameter.
  10651. IMPORTANT
  10652. IMPORTANT
  10653. Most sound components do not need to implement the SoundComponentAddSource function. Only sound components that can handle more than one source of input need to define it.s
  10654. SPECIAL CONSIDERATIONS
  10655. The SoundComponentAddSource function is called at noninterrupt time.
  10656. RESULT CODES
  10657. Your SoundComponentAddSource function should return noErr if successful or an appropriate result code otherwise.
  10658. SEE ALSO
  10659. See page 5-33 for a description of OpenMixerSoundComponent.
  10660. SoundComponentRemoveSource
  10661.  
  10662. A sound output device component that implements the SoundComponentAddSource function must also implement the SoundComponentRemoveSource function to remove sound sources.
  10663. pascal ComponentResult SoundComponentRemoveSource 
  10664.                             (ComponentInstance ti, SoundSource sourceID);
  10665. ti    A component instance that identifies your sound component.
  10666. sourceID    A source ID for the source component chain to be removed.
  10667. DESCRIPTION
  10668. Your SoundComponentRemoveSource function is called by the Sound Manager to remove the existing sound source specified by the sourceID parameter. Your SoundComponentRemoveSource function should do whatever is necessary to invalidate that source and then call through to the Apple Mixer’s SoundComponentRemoveSource function.
  10669. IMPORTANT
  10670. Most sound components do not need to implement the SoundComponentRemoveSource function. Only sound components that can handle more than one source of input need to define it.s
  10671. SPECIAL CONSIDERATIONS
  10672. Your SoundComponentRemoveSource function is always called at noninterrupt time.
  10673. RESULT CODES
  10674. Your SoundComponentRemoveSource function should return noErr if successful or an appropriate result code otherwise.
  10675. Getting and Setting Sound Component Information
  10676.  
  10677. To write a sound component, you need to define two routines that determine the capabilities of your component or to change those capabilities:
  10678. n    SoundComponentGetInfo
  10679. n    SoundComponentSetInfo
  10680. SoundComponentGetInfo
  10681.  
  10682. A sound component must implement the SoundComponentGetInfo function. The Sound Manager calls this function to get information about the capabilities of your component.
  10683. pascal ComponentResult SoundComponentGetInfo 
  10684.                                     (ComponentInstance ti, 
  10685.                                         SoundSource sourceID,
  10686.                                         OSType selector, void *infoPtr);
  10687. ti    A component instance that identifies your sound component.
  10688. sourceID    A source ID for a source component chain.
  10689. selector    A sound component information selector. See “Sound Component Information Selectors” beginning on page 5-22 for a description of the available selectors.
  10690. infoPtr    On output, a pointer to the information requested by the caller.
  10691. DESCRIPTION
  10692. Your SoundComponentGetInfo function returns information about your sound component. The sourceID parameter specifies the sound source to return information about, and the selector parameter specifies the kind of information to be returned. If the information occupies 4 or fewer bytes, it should be returned in the location pointed to by the infoPtr parameter. If the information is larger than 4 bytes, the infoPtr parameter is a pointer to a component information list, a 6-byte structure of type SoundInfoList:
  10693. typedef struct {
  10694.     short                    count;
  10695.     Handle                    handle;
  10696. } SoundInfoList, *SoundInfoListPtr;
  10697. This structure consists of a count and a handle to a variable-sized array. The count field specifies the number of elements in the array to which handle is a handle. It is your component’s responsibility to allocate the block of data referenced by that handle, but it is the caller’s responsibility to dispose of that handle once it is finished with it.
  10698. The data type of the array elements depends on the kind of information being returned. For example, the selector siSampleSizeAvailable indicates that you should return a list of the sample sizes your component can support. You return the information by passing back, in the infoPtr parameter, a pointer to an integer followed by a handle to an array of integers.
  10699. If your component cannot provide the information specified by the selector parameter, it should pass the selector to its source component.
  10700. SPECIAL CONSIDERATIONS
  10701. Your SoundComponentGetInfo function is not called at interrupt time if it is passed a selector that might cause it to allocate memory for the handle in the component information list.
  10702. RESULT CODES
  10703. Your SoundComponentGetInfo function should return noErr if successful or an appropriate result code otherwise.
  10704. SEE ALSO
  10705. See “Finding and Changing Component Capabilities” on page 5-18 for a sample SoundComponentGetInfo function.
  10706. SoundComponentSetInfo
  10707.  
  10708. A sound component must implement the SoundComponentSetInfo function. The Sound Manager calls this function to modify settings of your component.
  10709. pascal ComponentResult SoundComponentSetInfo 
  10710.                                     (ComponentInstance ti, 
  10711.                                         SoundSource sourceID,
  10712.                                         OSType selector, void *infoPtr);
  10713. ti    A component instance that identifies your sound component.
  10714. sourceID    A source ID for a source component chain.
  10715. selector    A sound component information selector. See “Sound Component Information Selectors” beginning on page 5-22 for a description of the available selectors.
  10716. infoPtr    A pointer to the information your component is to use to modify its settings. If the information occupies 4 or fewer bytes, however, this parameter contains the information itself, not the address of the information.
  10717. DESCRIPTION
  10718. Your SoundComponentSetInfo function is called by the Sound Manager to set one of the settings for your component, as specified by the selector parameter. If the information associated with that selector occupies 4 or fewer bytes, it is passed on the stack, in the infoPtr parameter itself. Otherwise, the infoPtr parameter is a pointer to a structure of type SoundInfoList. See the description of SoundComponentGetInfo for more information about the SoundInfoList structure.
  10719. If your component cannot modify the settings specified by the selector parameter, it should pass the selector to its source component.
  10720. RESULT CODES
  10721. Your SoundComponentSetInfo function should return noErr if successful or an appropriate result code otherwise.
  10722. Managing Source Data
  10723.  
  10724. To write a sound output device component, you might need to define routines that manage the flow of data in a sound channel:
  10725. n    SoundComponentStartSource
  10726. n    SoundComponentStopSource
  10727. n    SoundComponentPauseSource
  10728. n    SoundComponentPlaySourceBuffer
  10729. SoundComponentStartSource
  10730.  
  10731. A sound output device component must implement the SoundComponentStartSource function. The Sound Manager calls this function to start playing sounds in one or more sound channels.
  10732. pascal ComponentResult SoundComponentStartSource 
  10733.                                     (ComponentInstance ti, 
  10734.                                         short count, SoundSource *sources);
  10735. ti    A component instance that identifies your sound component.
  10736. count    The number of source IDs in the array pointed to by the source parameter.
  10737. sources    An array of source IDs.
  10738. DESCRIPTION
  10739. Your SoundComponentStartSource function is called by the Sound Manager to begin playing the sounds originating from the sound sources specified by the sources parameter. Your function should start (or resume) sending data from those sources to the associated sound output device. If your component supports only one sound source, you can ignore the sources parameter.
  10740. SPECIAL CONSIDERATIONS
  10741. Your SoundComponentStartSource function can be called at interrupt time.
  10742. RESULT CODES
  10743. Your SoundComponentStartSource function should return noErr if successful or an appropriate result code otherwise. You should return noErr even if no sounds are playing in the specified channels.
  10744. SoundComponentStopSource
  10745.  
  10746. A sound output device component must implement the SoundComponentStopSource function. The Sound Manager calls this function to stop playing sounds in one or more sound channels.
  10747. pascal ComponentResult SoundComponentStopSource 
  10748.                                     (ComponentInstance ti, short count, 
  10749.                                         SoundSource *sources);
  10750. ti    A component instance that identifies your sound component.
  10751. count    The number of source IDs in the array pointed to by the source parameter.
  10752. sources    An array of source IDs.
  10753. DESCRIPTION
  10754. Your SoundComponentStopSource function is called by the Sound Manager to stop the sounds originating from the sound sources specified by the sources parameter. Your function should stop sending data from those sources to the associated sound output device. In addition, your SoundComponentStopSource function should flush any data from the specified sound sources that it’s caching. If your component supports only one sound source, you can ignore the sources parameter.
  10755. RESULT CODES
  10756. Your SoundComponentStopSource function should return noErr if successful or an appropriate result code otherwise. You should return noErr even if no sounds are playing in the specified channels.
  10757. SoundComponentPauseSource
  10758.  
  10759. A sound output device component must implement the SoundComponentPauseSource function. The Sound Manager calls this function to stop pause the playing of sounds in one or more sound channels.
  10760. pascal ComponentResult SoundComponentPauseSource 
  10761.                                     (ComponentInstance ti, 
  10762.                                         short count, SoundSource *sources);
  10763. ti    A component instance that identifies your sound component.
  10764. count    The number of source IDs in the array pointed to by the source parameter.
  10765. sources    An array of source IDs.
  10766. DESCRIPTION
  10767. Your SoundComponentPauseSource function is called by the Sound Manager to pause the playing of the sounds originating from the sound sources specified by the sources parameter. Your function should stop sending data from those sources to the associated sound output device. Because your SoundComponentStartSource function might be called to resume playing sounds, you should not flush any data. If your component supports only one sound source, you can ignore the sources parameter.
  10768. RESULT CODES
  10769. Your SoundComponentPauseSource function should return noErr if successful or an appropriate result code otherwise. You should return noErr even if no sounds are playing in the specified channels.
  10770. SoundComponentPlaySourceBuffer
  10771.  
  10772. A sound component must implement the SoundComponentPlaySourceBuffer function. The Sound Manager calls this function to start a new sound playing.
  10773. pascal ComponentResult SoundComponentPlaySourceBuffer 
  10774.                                         (ComponentInstance ti, 
  10775.                                             SoundSource sourceID, 
  10776.                                             SoundParamBlockPtr pb, 
  10777.                                             long actions);
  10778. ti    A component instance that identifies your sound component.
  10779. sourceID    A source ID for a source component chain.
  10780. pb    A pointer to a sound parameter block.
  10781. actions    A set of 32 bit flags that describe the actions to be taken when preparing to play the source data. See “Action Flags” on page 5-27 for a description of the constants you can use to select bits in this parameter.
  10782. DESCRIPTION
  10783. Your SoundComponentPlaySourceBuffer function is called by the Sound Manager to start a new sound playing. The sound parameter block pointed to by the pb parameter specifies the sound to be played. That parameter block should be passed successively to all sound components in the chain specified by the sourceID parameter. This allows the components to determine their output formats and playback settings and to prepare for a subsequent call to their SoundComponentGetSourceData function. It also allows a sound output device component to prepare for starting up its associated hardware.
  10784. RESULT CODES
  10785. Your SoundComponentPlaySourceBuffer function should return noErr if successful or an appropriate result code otherwise.
  10786.  
  10787.  
  10788. Summary of Sound Components
  10789.  
  10790. This section provides a C summary for the constants, data types, and routines you can use to write a sound component. There are currently no Pascal interfaces available for writing sound components.
  10791. C Summary
  10792.  
  10793. Constants
  10794.  
  10795. /*component types*/
  10796. #define kSoundComponentType                                            'sift'            /*utility component*/
  10797. #define kMixerType                                            'mixr'            /*mixer component*/
  10798. #define kSoundHardwareType                                            'sdev'            /*sound output device component*/
  10799. #define kSoundCompressor                                            'scom'            /*compression component*/
  10800. #define kSoundDecompressor                                            'sdec'            /*decompression component*/
  10801. #define kNoSoundComponentType                                            '****'            /*no type*/
  10802. /*subtypes for kSoundComponentType component type*/
  10803. #define kRate8SubType                                            'ratb'            /*8-bit rate converter*/
  10804. #define kRate16SubType                                            'ratw'            /*16-bit rate converter*/
  10805. #define kConverterSubType                                            'conv'            /*sample format converter*/
  10806. #define kSndSourceSubType                                            'sour'            /*generic source component*/
  10807. /*subtypes for kMixerType component type*/
  10808. #define kMixer8SubType                                            'mixb'            /*8-bit mixer*/
  10809. #define kMixer16SubType                                            'mixw'            /*16-bit mixer*/
  10810. /*subtypes for kSoundHardwareType component type*/
  10811. #define kClassicSubType                                            'clas'            /*Classic hardware*/
  10812. #define kASCSubType                                            'asc '            /*ASC device*/
  10813. #define kDSPSubType                                            'dsp '            /*DSP device*/
  10814. /*subtypes for kSoundCompressor and kSoundDecompressor component types*/
  10815. #define kMace3SubType                                            'MAC3'            /*MACE 3:1*/
  10816. #define kMace6SubType                                            'MAC6 '            /*MACE 6:1*/
  10817. #define kCDXA4SubType                                            'CDX4'            /*CD/XA 4:1*/
  10818. #define kCDXA2SubType                                            'CDX2'            /*CD/XA 2:1*/
  10819. #define kSoundComponentCodeType                                            'sift'            /*sound component code type*/
  10820. /*first selector that can be delegated up the chain*/
  10821. #define kDelegatedSoundComponentSelectors                                                                0x0100
  10822. /*Component Manager selectors for routines*/
  10823. enum {
  10824.     /*the following calls cannot be delegated*/
  10825.     kSoundComponentInitOutputDeviceSelect                                                        = 1,
  10826.     kSoundComponentSetSourceSelect,
  10827.     kSoundComponentGetSourceSelect,
  10828.     kSoundComponentGetSourceDataSelect,
  10829.     kSoundComponentSetOutputSelect,
  10830.     /*the following calls can be delegated*/
  10831.     kSoundComponentAddSourceSelect = kDelegatedSoundComponentSelectors + 1,
  10832.     kSoundComponentRemoveSourceSelect,
  10833.     kSoundComponentGetInfoSelect,
  10834.     kSoundComponentSetInfoSelect,
  10835.     kSoundComponentStartSourceSelect,
  10836.     kSoundComponentStopSourceSelect,
  10837.     kSoundComponentPauseSourceSelect,
  10838.     kSoundComponentPlaySourceBufferSelect
  10839. };
  10840. /*sound component information selectors*/
  10841. #define siChannelAvailable                                            'chav'            /*number of channels available*/
  10842. #define siCompressionAvailable                                            'cmav'            /*compression types available*/
  10843. #define siCompressionFactor                                            'cmfa'            /*current compression factor*/
  10844. #define siCompressionType                                            'comp'            /*current compression type*/
  10845. #define siHardwareMute                                            'hmut'            /*current hardware mute state*/
  10846. #define siHardwareVolume                                            'hvol'            /*current hardware volume*/
  10847. #define siHardwareVolumeSteps                                            'hstp'            /*number of hardware volume steps*/
  10848. #define siHeadphoneMute                                            'pmut'            /*current headphone mute state*/
  10849. #define siHeadphoneVolume                                            'pvol'            /*current headphone volume*/
  10850. #define siHeadphoneVolumeSteps                                            'hdst'            /*num. of headphone volume steps*/
  10851. #define siNumberChannels                                            'chan'            /*current number of channels*/
  10852. #define siQuality                                            'qual'            /*current quality*/
  10853. #define siRateMultiplier                                            'rmul'            /*current rate multiplier*/
  10854. #define siSampleRate                                            'srat'            /*current sample rate*/
  10855. #define siSampleRateAvailable                                            'srav'            /*sample rates available*/
  10856. #define siSampleSize                                            'ssiz'            /*current sample size*/
  10857. #define siSampleSizeAvailable                                            'ssav'            /*sample sizes available*/
  10858. #define siSpeakerMute                                            'smut'            /*current speaker mute*/
  10859. #define siSpeakerVolume                                            'svol'            /*current speaker volume*/
  10860. #define siVolume                                            'volu'            /*current volume setting*/
  10861. /*audio data format types*/
  10862. #define kOffsetBinary                                            'raw '
  10863. #define kTwosComplement                                            'twos'
  10864. #define kMACE3Compression                                            'MAC3'
  10865. #define kMACE6Compression                                            'MAC6'
  10866. /*sound component features flags*/
  10867. #define k8BitRawIn                                            (1 << 0)                /*data flags*/
  10868. #define k8BitTwosIn                                            (1 << 1)
  10869. #define k16BitIn                                            (1 << 2)
  10870. #define kStereoIn                                            (1 << 3)
  10871. #define k8BitRawOut                                            (1 << 8)
  10872. #define k8BitTwosOut                                            (1 << 9)
  10873. #define k16BitOut                                            (1 << 10)
  10874. #define kStereoOut                                            (1 << 11)
  10875.  
  10876. #define kReverse                                            (1 << 16)                /*action flags*/
  10877. #define kRateConvert                                            (1 << 17)
  10878. #define kCreateSoundSource                                            (1 << 18)
  10879.  
  10880. #define kHighQuality                                            (1 << 22)                /*performance flags*/
  10881. #define kRealTime                                            (1 << 23)
  10882. /*action flags for SoundComponentPlaySourceBuffer*/
  10883. #define kSourcePaused                                            (1 << 0)
  10884. #define kPassThrough                                            (1 << 16)
  10885. #define kNoSoundComponentChain                                            (1 << 17)
  10886. /*flags for OpenMixerSoundComponent*/
  10887. #define kNoMixing                                            (1 << 0)                /*don't mix sources*/
  10888. #define kNoSampleRateConversion                                            (1 << 1)                /*don't convert sample rate*/
  10889. #define kNoSampleSizeConversion                                            (1 << 2)                /*don't convert sample size*/
  10890. #define kNoSampleFormatConversion                                                            \
  10891.                                             (1 << 3)                /*don't convert sample format*/
  10892. #define kNoChannelConversion                                            (1 << 4)                /*don't convert stereo/mono*/
  10893. #define kNoDecompression                                            (1 << 5)                /*don't decompress*/
  10894. #define kNoVolumeConversion                                            (1 << 6)                /*don't apply volume*/
  10895. #define kNoRealtimeProcessing                                            (1 << 7)                /*don't run at interrupt time*/
  10896. /*quality flags*/
  10897. #define kBestQuality                                            (1 << 0)                /*use interp. in rate conv.*/
  10898. /*volume specifications*/
  10899. #define kSilenceByte                                             0x80
  10900. #define kSilenceLong                                             0x80808080
  10901. #define kFullVolume                                            0x0100
  10902. Data Types
  10903.  
  10904. Unsigned Fixed-Point Numbers
  10905. typedef unsigned long UnsignedFixed;                                                    /*unsigned fixed-point number*/
  10906. Sound Component Data Record
  10907. typedef struct {
  10908.     long                    flags;                            /*sound component flags*/
  10909.     OSType                    format;                            /*data format*/
  10910.     short                    numChannels;                            /*number of channels in data*/
  10911.     short                    sampleSize;                            /*size of a sample*/
  10912.     UnsignedFixed                    sampleRate;                            /*sample rate*/
  10913.     long                    sampleCount;                            /*number of samples in buffer*/
  10914.     Byte                    *buffer;                            /*location of data*/
  10915.     long                    reserved;                            /*reserved*/
  10916. } SoundComponentData, *SoundComponentDataPtr;
  10917. Sound Parameter Block
  10918. typedef pascal Boolean (*SoundParamProcPtr)(SoundParamBlockPtr *pb);
  10919. struct SoundParamBlock {
  10920.     long                            recordSize;                    /*size of this record in bytes*/
  10921.     SoundComponentData                            desc;                    /*description of sound buffer*/
  10922.     Fixed                            rateMultiplier;                    /*rate multiplier*/
  10923.     short                            leftVolume;                    /*volume on left channel*/
  10924.     short                            rightVolume;                    /*volume on right channel*/
  10925.     long                            quality;                    /*quality*/
  10926.     ComponentInstance                            filter;                    /*filter*/
  10927.     SoundParamProcPtr                            moreRtn;                    /*routine to call to get more data*/
  10928.     SoundParamProcPtr                            completionRtn;                    /*buffer complete routine*/
  10929.     long                            refCon;                    /*user refcon*/
  10930.     short                            result;                    /*result*/
  10931. };
  10932. typedef struct SoundParamBlock SoundParamBlock;
  10933. typedef SoundParamBlock *SoundParamBlockPtr;
  10934. Sound Source
  10935. typedef struct privateSoundSource *SoundSource;
  10936. Sound Information List
  10937. typedef struct {
  10938.     short                    count;
  10939.     Handle                    handle;
  10940. } SoundInfoList, *SoundInfoListPtr;
  10941. Compression Information Record
  10942. typedef struct {
  10943.     long                    recordSize;
  10944.     OSType                    format;
  10945.     short                    compressionID;
  10946.     short                    samplesPerPacket;
  10947.     short                    bytesPerPacket;
  10948.     short                    bytesPerFrame;
  10949.     short                    bytesPerSample;
  10950.     short                    futureUse1;
  10951. } CompressionInfo, *CompressionInfoPtr, **CompressionInfoHandle;
  10952. Sound Manager Utilities
  10953.  
  10954. Opening and Closing the Apple Mixer Component
  10955. pascal OSErr OpenMixerSoundComponent
  10956. (SoundComponentDataPtr outputDescription, 
  10957. long outputFlags, 
  10958. ComponentInstance *mixerComponent);
  10959. pascal OSErr CloseMixerSoundComponent
  10960. (ComponentInstance ci);
  10961. Saving and Restoring Sound Component Preferences
  10962. pascal OSErr SetSoundPreference
  10963. (OSType type, Str255 name, Handle settings);
  10964. pascal OSErr GetSoundPreference
  10965. (OSType type, Str255 name, Handle settings);
  10966. Sound Component-Defined Routines
  10967.  
  10968. Managing Sound Components
  10969. pascal ComponentResult SoundComponentInitOutputDevice
  10970. (ComponentInstance ti, long actions);
  10971. pascal ComponentResult SoundComponentSetSource
  10972. (ComponentInstance ti, SoundSource sourceID,
  10973. ComponentInstance source);
  10974. pascal ComponentResult SoundComponentGetSource
  10975. (ComponentInstance ti, SoundSource sourceID,
  10976. ComponentInstance *source);
  10977. pascal ComponentResult SoundComponentGetSourceData
  10978. (ComponentInstance ti, 
  10979. SoundComponentDataPtr *sourceData);
  10980. pascal ComponentResult SoundComponentSetOutput
  10981. (ComponentInstance ti, 
  10982. SoundComponentDataPtr requested, SoundComponentDataPtr *actual);
  10983. Creating and Removing Audio Sources
  10984. pascal ComponentResult SoundComponentAddSource
  10985. (ComponentInstance ti, SoundSource *sourceID);
  10986. pascal ComponentResult SoundComponentRemoveSource
  10987. (ComponentInstance ti, SoundSource sourceID);
  10988. Getting and Setting Sound Component Information
  10989. pascal ComponentResult SoundComponentGetInfo
  10990. (ComponentInstance ti, SoundSource sourceID,
  10991. OSType selector, void *infoPtr);
  10992. pascal ComponentResult SoundComponentSetInfo
  10993. (ComponentInstance ti, SoundSource sourceID,
  10994. OSType selector, void *infoPtr);
  10995. Managing Source Data
  10996. pascal ComponentResult SoundComponentStartSource
  10997. (ComponentInstance ti, short count, 
  10998. SoundSource *sources);
  10999. pascal ComponentResult SoundComponentStopSource
  11000. (ComponentInstance ti, short count, 
  11001. SoundSource *sources);
  11002. pascal ComponentResult SoundComponentPauseSource
  11003. (ComponentInstance ti, short count, 
  11004. SoundSource *sources);
  11005. pascal ComponentResult SoundComponentPlaySourceBuffer
  11006. (ComponentInstance ti, SoundSource sourceID, SoundParamBlockPtr pb, long actions);
  11007. Assembly-Language Summary
  11008.  
  11009. Data Structures
  11010.  
  11011. Sound Component Data Record0    flags    long    sound component flags    
  11012. 4    format    long    data format    
  11013. 8    numChannels    word    number of channels in data    
  11014. 10    sampleSize    word    size of a sample    
  11015. 12    sampleRate    long    sample rate (Fixed)    
  11016. 16    sampleCount    long    number of samples in buffer    
  11017. 20    buffer    long    location of data    
  11018. 24    reserved    long    reserved    
  11019.  
  11020. Sound Parameter Block0    recordSize    long    size of this record in bytes    
  11021. 4    desc    28 bytes    description of sound buffer    
  11022. 32    rateMultiplier    long    rate multiplier (Fixed)    
  11023. 36    leftVolume    word    volume on left channel    
  11024. 38    rightVolume    word    volume on right channel    
  11025. 40    quality    long    quality    
  11026. 44    filter    long    filter    
  11027. 48    moreRtn    long    routine to call to get more data    
  11028. 52    completionRtn    long    buffer complete routine    
  11029. 56    refCon    long    user refcon    
  11030. 60    result    word    result    
  11031.  
  11032. Sound Information List0    count    word    number of data items in the handle    
  11033. 2    handle    long    handle to list of data items    
  11034.  
  11035. Compression Information Record0    recordSize    long    the size of this record    
  11036. 4    format    4 bytes    compression format    
  11037. 8    compressionID    word    compression ID    
  11038. 10    samplesPerPacket    word    the number of samples per packet    
  11039. 12    bytesPerPacket    word    the number of bytes per packet    
  11040. 14    bytesPerFrame    word    the number of bytes per frame    
  11041. 16    bytesPerSample    word    the number of bytes per sample    
  11042. 18    futureUse1    word    reserved    
  11043.  
  11044. Listing 6-0
  11045. Table 6-0
  11046. Audio Components
  11047. Contents
  11048. About Audio Components6-3
  11049. Writing an Audio Component6-5
  11050. Creating an Audio Component6-5
  11051. Dispatching to Audio Component-Defined Routines6-7
  11052. Audio Components Reference6-8
  11053. Data Structures6-8
  11054. Audio Information Records6-9
  11055. Audio Component-Defined Routines6-9
  11056. Getting and Setting Volumes6-10
  11057. Managing the Mute State6-11
  11058. Resetting Audio Components6-13
  11059. Getting Audio Component Information6-13
  11060. Summary of Audio Components6-15
  11061. C Summary6-15
  11062. Constants6-15
  11063. Data Types6-16
  11064. Audio Component-Defined Routines6-16
  11065. Assembly-Language Summary6-17
  11066. Data Structures6-17
  11067. Audio Components
  11068. This chapter describes audio components, which are code modules used by the Sound Manager to adjust volumes or other settings of a sound output device. In general, you need to write an audio component only if you are developing a sound output device with multiple output ports that can be independently controlled by software. If your sound output device has only one software-controllable output port, the sound output device component for that device manages the volume levels of the port.
  11069. IMPORTANT
  11070. The Sound Manager loads and manages audio components, which operate transparently to applications. The routines described in this chapter are intended for use exclusively by audio components.s
  11071. To use this chapter, you should already be familiar with writing sound output device components, as described in the chapter “Sound Components” in this book. Because audio components are components, you also need to be familiar with the Component Manager, described in Inside Macintosh: More Macintosh Toolbox.
  11072. This chapter begins by describing what audio components are and the Sound Manager uses them. Then it provides instructions on how to write an audio component. The section “Audio Components Reference” beginning on page 6-8 describes the routines that your audio component might need to define.
  11073. Note
  11074. Pascal interfaces for audio components are not currently available. As a result, this chapter provides all source code examples and reference materials in C.u
  11075.  
  11076. About Audio Components
  11077.  
  11078. An audio component is a component that works with the Sound Manager to adjust volumes or other settings of a sound output device. The Sound Manager uses audio components, however, only when a particular sound output device has more than one audio port that can be controlled through software. If a sound output device has only one audio port, the sound component that communicates with the output device controls the volume settings of that port.
  11079. IMPORTANT
  11080. Because audio components are currently used to manage only volume and mute settings, they might have been called volume components. The more general term anticipates future capabilities of audio components. For example, audio components might in the future be used to modify bass or treble settings of an audio port.s
  11081. An audio port is any independently controllable sound-producing hardware connected or attached to a sound output device. For example, the Apple AudioVision 14 Display (shown in Figure 6-1) contains two audio ports: a set of speakers and a jack for headphones.
  11082. Figure 6-1    The Apple AudioVision 14 Display
  11083.  
  11084. As the Volumes subpanel of the Sound control panel shows (Figure 6-2), the two audio ports are independently controllable by software.
  11085. Figure 6-2    The Volumes control panel for the Apple AudioVision 14 Display
  11086.  
  11087. The control panel shown in Figure 6-2 contains volume sliders both for the set of speakers and for the headphones. The volume of the speakers is controlled by the sound component that drives the sound output device. The volume of the headphones is controlled by an audio component.
  11088. In short, audio components are used to allow a single sound output device to have more than one audio port. The sound component that communicates with that device can control the volume setting of one audio port; audio components control the volume settings of all other audio ports.
  11089.  
  11090. Writing an Audio Component
  11091.  
  11092. Because an audio component is a component, it must be able to respond to standard selectors sent by the Component Manager. In addition, an audio component must handle other selectors specific to audio components. This section briefly describes how to write an audio component.
  11093. Creating an Audio Component
  11094.  
  11095. An audio component is a component. It contains a number of resources, including icons, strings, and the standard component resource (a resource of type 'thng') required of any Component Manager component. In addition, an audio component must contain code to handle required selectors passed to it by the Component Manager as well as selectors specific to the audio component.
  11096. Note
  11097. For complete details on components and their structure, see the chapter “Component Manager” in Inside Macintosh: More Macintosh Toolbox. This section provides specific information about audio components.u
  11098. The component resource binds together all the relevant resources contained in a component; its structure is defined by the ComponentResource data type.
  11099. struct ComponentResource {
  11100.     ComponentDescription                                 cd;
  11101.     ResourceSpec                                 component;
  11102.     ResourceSpec                                 componentName
  11103.     ResourceSpec                                componentInfo;
  11104.     ResourceSpec                                componentIcon;
  11105. };
  11106. The component field specifies the resource type and resource ID of the component’s executable code. By convention, this field should be set to the value kAudioCodeType.
  11107. #define kAudioCodeType                                    'adio'            /*audio component code type*/
  11108. (You can, however, specify some other resource type if you wish.) The resource ID can be any integer greater than or equal to 128. See the following section for further information about this code resource.
  11109. The componentName field specifies the resource type and resource ID of the resource that contains the component’s name. Usually the name is contained in a resource of type 'STR '. This string should be as short as possible.
  11110. The componentInfo field specifies the resource type and resource ID of the resource that contains a description of the component. Usually the description is contained in a resource of type 'STR '.
  11111. The componentIcon field specifies the resource type and resource ID of the resource that contains an icon for the component. Usually the icon is contained in a resource of type 'ICON'.
  11112. The cd field of the ComponentResource structure is a component description record, which contains additional information about the component. A component description record is defined by the ComponentDescription data type.
  11113. typedef struct {
  11114.     OSType                                componentType;
  11115.     OSType                                componentSubType;
  11116.     OSType                                componentManufacturer;
  11117.     unsigned long                                componentFlags;
  11118.     unsigned long                                componentFlagsMask;
  11119. } ComponentDescription;
  11120. For audio components, the componentType field must be set to a value recognized by the Sound Manager.
  11121. #define kAudioComponentType                                            'adio'            /*audio component*/
  11122. In addition, the componentSubType field must be set to a value that indicates the type of audio services your component provides. For example, the Apple-supplied audio components have these subtypes:
  11123. #define kAwacsPhoneSubType                                                    'hphn'            /*AWACS phone*/
  11124. #define kAudioVisionSpeakerSubType                                                    'telc'            /*AudioVision speaker*/
  11125. #define kAudioVisionHeadphoneSubType                                                    'telh'            /*AudioVision headphones*/
  11126. If you write an audio component, you should define some other subtype.
  11127. Note
  11128. Apple Computer, Inc., reserves for its own use all types and subtypes composed solely of lowercase letters.u
  11129. You can assign any value you like to the componentManufacturer field; typically you put the signature of your audio component in this field.
  11130. The componentFlags field of the component description for an audio component contains bit flags that encode information about the component. You can use this field to specify that the Component Manager should send your component the kComponentRegisterSelect selector.
  11131. enum {
  11132.     cmpWantsRegisterMessage                                    = 1L<<31            /*send register request*/
  11133. };
  11134. This bit is useful for audio components, which might need to test for the presence of the appropriate hardware to determine whether to register with the Component Manager. When your component gets the kComponentRegisterSelect selector at system startup time, it should make sure that all the necessary hardware is available. If it isn’t available, your component shouldn’t register.
  11135. You should set the componentFlagsMask field to 0.
  11136. Your audio component is contained in a resource file. You can assign any type you wish to be the file creator, but the type of the file must be 'thng'. If the audio component contains a 'BNDL' resource, then the file’s bundle bit must be set.
  11137. Dispatching to Audio Component-Defined Routines
  11138.  
  11139. As explained in the previous section, the code stored in the audio component should be contained in a resource of type kAudioCodeType. The Component Manager expects the entry point in this resource to be a function with this format:
  11140. pascal ComponentResult MyAudioDispatch (ComponentParameters *params, 
  11141.                                                         AudioGlobalsPtr globals);
  11142. The Component Manager calls your sound component by passing MyAudioDispatch a selector in the params->what field; MyAudioDispatch must interpret the selector and possibly dispatch to some other routine in the resource. Your audio component must be able to handle the required selectors, defined by these constants:
  11143. #define kComponentOpenSelect                                                     -1
  11144. #define kComponentCloseSelect                                                     -2
  11145. #define kComponentCanDoSelect                                                     -3
  11146. #define kComponentVersionSelect                                                     -4
  11147. #define kComponentRegisterSelect                                                     -5
  11148. #define kComponentTargetSelect                                                      -6
  11149. #define kComponentUnregisterSelect                                                     -7
  11150. Note
  11151. For complete details on required component selectors, see the chapter “Component Manager” in Inside Macintosh: More Macintosh Toolbox.u
  11152. In addition, your audio component must be able to respond to component-specific selectors. The Sound Manager can pass these selectors to your audio component:
  11153. enum {
  11154.     kAudioGetVolumeSelect = 0,
  11155.     kAudioSetVolumeSelect,
  11156.     kAudioGetMuteSelect,
  11157.     kAudioSetMuteSelect,
  11158.     kAudioSetToDefaultsSelect,
  11159.     kAudioGetInfoSelect
  11160. };
  11161. You can respond to these selectors by calling the Component Manager routine CallComponentFunctionWithStorage. See the section “Audio Component-Defined Routines” beginning on page 6-9 for information on how to handle these selectors.
  11162. In all likelihood, your component is loaded into the system heap, although it might be loaded into an application heap if memory is low in the system heap. You can call the Component Manager function GetComponentInstanceA5 to determine the A5 value of the current application. If this function returns 0, your component is in the system heap; otherwise, your component is in an application’s heap. Its location might affect how you allocate memory. For example, calling the MoveHHi routine on handles in the system heap has no result. Thus, you should either call the ReserveMemSys routine before calling NewHandleSys (so that the handle is allocated as low in the system heap as possible) or else just allocate a nonrelocatable block by calling the NewPtrSys routine.
  11163. If you need to access resources that are stored in your audio component, you can use OpenComponentResFile and CloseComponentResFile. OpenComponentResFile requires the ComponentInstance parameter supplied to your routine. You should not call Resource Manager routines such as OpenResFile or CloseResFile.
  11164. sWARNING
  11165. Do not leave any resource files open when your audio component is closed. Their maps will be left in the subheap when the subheap is freed, causing the Resource Manager to crash.s
  11166.  
  11167. Audio Components Reference
  11168.  
  11169. This section describes the data structures you can use to write an audio component. It also describes the routines that your audio component should call in response to an audio component selector. See “Writing an Audio Component” beginning on page 6-5 for information on creating a component that contains these component-defined routines.
  11170. Data Structures
  11171.  
  11172. This section describes the data structure you need to use when writing an audio component.
  11173. Audio Information Records
  11174.  
  11175. You return information about the capabilities of your audio component in the info parameter passed to your AudioGetInfo function. The info parameter contains a pointer to an audio information record. An audio information record is defined by the AudioInfo data type.
  11176. typedef struct {
  11177.     long                    capabilitiesFlags;                            /*device capabilities*/
  11178.     long                    reserved;                            /*reserved*/
  11179.     unsigned short                    numVolumeSteps;                            /*number of volume steps*/
  11180. } AudioInfo, *AudioInfoPtr;
  11181. Field descriptions
  11182. capabilitiesFlags
  11183. A set of bit flags specifying the capabilities of the audio component. You can use constants to set some of these bits:
  11184. #define audioDoesMono                                                    (1L<<0)            /*supports mono output*/
  11185. #define audioDoesStereo                                                    (1L<<1)            /*supports stereo output*/
  11186. #define audioDoesIndependentChannels                                                     (1L<<2)            /*supports independent 
  11187.                                                         software control of each channel*/
  11188. reserved    Reserved for use by Apple Computer, Inc.
  11189. numVolumeSteps
  11190. The number of volume steps your audio component supports.
  11191. Audio Component-Defined Routines
  11192.  
  11193. This section describes the routines you must define in order to write an audio component. You need to write routines to
  11194. n    get and set volume levels of a sound output device
  11195. n    manage mute states
  11196. n    reset device settings
  11197. n    get information about the audio component
  11198. All routines return result codes. If they succeed, they should return noErr. To simplify dispatching, the Component Manager requires these routines to return a value of type ComponentResult.
  11199. See “Writing an Audio Component” beginning on page 6-5 for a description of how you call these routines from within an audio component.
  11200. Getting and Setting Volumes
  11201.  
  11202. To write an audio component, you might need to define two routines that manage the volume level of the associated audio port:
  11203. n    AudioGetVolume
  11204. n    AudioSetVolume
  11205. AudioGetVolume
  11206.  
  11207. An audio component can implement the AudioGetVolume function. The Sound Manager calls this function to determine the current volume of an audio port.
  11208. pascal ComponentResult AudioGetVolume (ComponentInstance ac,
  11209.                                                         short whichChannel, 
  11210.                                                         ShortFixed *volume);
  11211. ac    A component instance that identifies your audio component.
  11212. whichChannel
  11213. The channel or channels whose volume you should return.
  11214. volume
  11215. On output, the current volume level of the specified channel.
  11216. DESCRIPTION
  11217. Your AudioGetVolume function is called by the Sound Manager to determine the current volume levels of one or more channels of an audio port. The volume parameter can have any value between 0 and 1, where 0 indicates minimum volume and 1 indicates maximum volume. The whichChannel parameter indicates the channels or channels whose volumes you should return. The following constants are defined for the whichChannel parameter:
  11218. #define audioAllChannels                                            0            /*all channels*/
  11219. #define audioLeftChannel                                             1            /*left channel*/
  11220. #define audioRightChannel                                            2            /*right channel*/
  11221. RESULT CODES
  11222. Your AudioGetVolume function should return noErr if successful or an appropriate result code otherwise. In particular, if your audio component doesn’t support software control of volume levels, AudioGetVolume should return unImpErr.
  11223. AudioSetVolume
  11224.  
  11225. An audio component can implement the AudioSetVolume function. The Sound Manager calls this function to set the current volume of an audio port.
  11226. pascal ComponentResult AudioSetVolume (ComponentInstance ac, 
  11227.                                                         short whichChannel, 
  11228.                                                         ShortFixed volume);
  11229. ac    A component instance that identifies your audio component.
  11230. whichChannel
  11231. The channel or channels whose volume you should set.
  11232. volume
  11233. The desired volume level of the specified channel.
  11234. DESCRIPTION
  11235. Your AudioSetVolume function is called by the Sound Manager to set the volume levels of one or more channels of an audio port. See the description of the AudioGetVolume function for the values of the whichChannel and volume parameters.
  11236. RESULT CODES
  11237. Your AudioSetVolume function should return noErr if successful or an appropriate result code otherwise. In particular, if your audio component doesn’t support software control of volume levels, AudioSetVolume should return unImpErr.
  11238. Managing the Mute State
  11239.  
  11240. To write an audio component, you might need to define two routines that manage the mute state of the associated audio port:
  11241. n    AudioGetMute
  11242. n    AudioSetMute
  11243. AudioGetMute
  11244.  
  11245. An audio component can implement the AudioGetMute function. The Sound Manager calls this function to determine the current mute state of an audio port.
  11246. pascal ComponentResult AudioGetMute (ComponentInstance ac, 
  11247.                                                     short whichChannel, 
  11248.                                                     short *mute);
  11249. ac    A component instance that identifies your audio component.
  11250. whichChannel
  11251. The channel or channels whose mute state you should return.
  11252. mute
  11253. On output, the current mute state of the specified channel.
  11254. DESCRIPTION
  11255. Your AudioGetMute function is called by the Sound Manager to determine the current mute state of one or more channels of an audio port. The following constants define the mute states you can return in the mute parameter:
  11256. #define audioUnmuted                                            0            /*device is not muted*/
  11257. #define audioMuted                                            1            /*device is muted*/
  11258. The whichChannel parameter indicates the channels or channels whose mute state you should return. The following constants are defined for the whichChannel parameter:
  11259. #define audioAllChannels                                            0            /*all channels*/
  11260. #define audioLeftChannel                                             1            /*left channel*/
  11261. #define audioRightChannel                                            2            /*right channel*/
  11262. RESULT CODES
  11263. Your AudioGetMute function should return noErr if successful or an appropriate result code otherwise. In particular, if your audio component doesn’t support software control of mute states, AudioGetMute should return unImpErr.
  11264. AudioSetMute
  11265.  
  11266. An audio component can implement the AudioSetMute function. The Sound Manager calls this function to set the current mute state of an audio port.
  11267. pascal ComponentResult AudioSetMute (ComponentInstance ac, 
  11268.                                                     short whichChannel, 
  11269.                                                     short mute);
  11270. ac    A component instance that identifies your audio component.
  11271. whichChannel
  11272. The channel or channels whose mute state you should set.
  11273. mute
  11274. The desired mute state of the specified channel.
  11275. DESCRIPTION
  11276. Your AudioSetMute function is called by the Sound Manager to set the mute state of one or more channels of an audio port. See the description of the AudioGetMute function for the values of the whichChannel and mute parameters.
  11277. RESULT CODES
  11278. Your AudioSetMute function should return noErr if successful or an appropriate result code otherwise. In particular, if your audio component doesn’t support software control of mute states, AudioSetMute should return unImpErr.
  11279. Resetting Audio Components
  11280.  
  11281. To write an audio component, you need to define the AudioSetToDefaults routine, which resets the associated audio port to its default settings.
  11282. AudioSetToDefaults
  11283.  
  11284. The Sound Manager might call your AudioSetToDefaults function to reset an audio port.
  11285. pascal ComponentResult AudioSetToDefaults (ComponentInstance ac);
  11286. ac    A component instance that identifies your audio component.
  11287. DESCRIPTION
  11288. Your AudioSetToDefaults function should reset its volume and mute levels to some reasonable default value. It should also reset to reasonable values any other settings it might be maintaining privately.
  11289. RESULT CODES
  11290. Your AudioSetToDefaults function should return noErr if successful or an appropriate result code otherwise.
  11291. Getting Audio Component Information
  11292.  
  11293. To write an audio component, you need to define the AudioGetInfo routine, which returns information about the capabilities of your component.
  11294. AudioGetInfo
  11295.  
  11296. An audio component must implement the AudioGetInfo function. The Sound Manager calls this function to get information about the capabilities of your component.
  11297. pascal ComponentResult AudioGetInfo (ComponentInstance ac, 
  11298.                                                         AudioInfoPtr info);
  11299. ac    A component instance that identifies your sound component.
  11300. info    A pointer to an audio information record.
  11301. DESCRIPTION
  11302. Your AudioGetInfo function returns information about your audio component. You should fill out the audio information record pointed to by the info parameter. See “Audio Information Records” beginning on page 6-9 for a description of the audio information record.
  11303. RESULT CODES
  11304. Your AudioGetInfo function should return noErr if successful or an appropriate result code otherwise.
  11305.  
  11306.  
  11307. Summary of Audio Components
  11308.  
  11309. This section provides a C summary for the constants, data types, and routines you can use to write an audio component. There are currently no Pascal interfaces available for writing audio components.
  11310. C Summary
  11311.  
  11312. Constants
  11313.  
  11314. /*component types*/
  11315. #define kAudioComponentType                                                    'adio'            /*audio component*/
  11316. /*subtypes for kAudioComponentType component type*/
  11317. #define kAwacsPhoneSubType                                                    'hphn'            /*AWACS phone*/
  11318. #define kAudioVisionSpeakerSubType                                                    'telc'            /*AudioVision speaker*/
  11319. #define kAudioVisionHeadphoneSubType                                                    'telh'            /*AudioVision headphones*/
  11320. #define kAudioCodeType                                                    'adio'            /*audio component code type*/
  11321. /*Component Manager selectors for routines*/
  11322. enum {
  11323.     kAudioGetVolumeSelect = 0,
  11324.     kAudioSetVolumeSelect,
  11325.     kAudioGetMuteSelect,
  11326.     kAudioSetMuteSelect,
  11327.     kAudioSetToDefaultsSelect,
  11328.     kAudioGetInfoSelect
  11329. };
  11330. /*values for whichChannel parameter*/
  11331. #define audioAllChannels                                            0            /*all channels*/
  11332. #define audioLeftChannel                                             1            /*left channel*/
  11333. #define audioRightChannel                                            2            /*right channel*/
  11334. /*values for mute parameter*/
  11335. #define audioUnmuted                                            0            /*device is not muted*/
  11336. #define audioMuted                                            1            /*device is muted*/
  11337. /*audio component features flags*/
  11338. #define audioDoesMono                                                    (1L<<0)            /*supports mono output*/
  11339. #define audioDoesStereo                                                    (1L<<1)            /*supports stereo output*/
  11340. #define audioDoesIndependentChannels                                                     (1L<<2)            /*supports independent 
  11341.                                                         software control of each channel*/
  11342. Data Types
  11343.  
  11344. Short Fixed-Point Numbers
  11345. typedef short ShortFixed;
  11346. Audio Information Record
  11347. typedef struct {
  11348.     long                    capabilitiesFlags;                            /*device capabilities*/
  11349.     long                    reserved;                            /*reserved*/
  11350.     unsigned short                    numVolumeSteps;                            /*number of volume steps*/
  11351. } AudioInfo, *AudioInfoPtr;
  11352. Audio Component-Defined Routines
  11353.  
  11354. Getting and Setting Volumes
  11355. pascal ComponentResult AudioGetVolume
  11356. (ComponentInstance ac, short whichChannel, ShortFixed *volume);
  11357. pascal ComponentResult AudioSetVolume
  11358. (ComponentInstance ac, short whichChannel, ShortFixed volume);
  11359. Managing the Mute State
  11360. pascal ComponentResult AudioGetMute
  11361. (ComponentInstance ac, short whichChannel, short *mute);
  11362. pascal ComponentResult AudioSetMute
  11363. (ComponentInstance ac, short whichChannel, short mute);
  11364. Resetting Audio Components
  11365. pascal ComponentResult AudioSetToDefaults
  11366. (ComponentInstance ac);
  11367. Getting Audio Component Information
  11368. pascal ComponentResult AudioGetInfo
  11369. (ComponentInstance ac, AudioInfoPtr info);
  11370. Assembly-Language Summary
  11371.  
  11372. Data Structures
  11373.  
  11374. Audio Information Record0    capabilitiesFlags    long    device capabilities    
  11375. 4    reserved    long    reserved    
  11376. 8    numVolumeSteps    word    number of volume steps    
  11377.  
  11378. Glossary
  11379.  
  11380.  
  11381. AGCSee automatic gain control.
  11382. AIFFSee Audio Interchange File Format.
  11383. AIFF-CSee Audio Interchange File Format Extension for Compression.
  11384. alert soundSee system alert sound.
  11385. Alert Sounds control panelA subpanel of the Sound control panel that allows the user to select a system alert sound. See also Sound In control panel, Sound Out control panel, Volumes control panel.
  11386. allophoneA distinct variety of a phoneme in a particular language that is never used contrastingly with any other allophone of the phoneme.
  11387. amplitudeA modification to the wave amplitude of a sound to make it sound louder or softer. See also speech volume. Compare wave amplitude.
  11388. Apple MixerSee Apple Mixer component.
  11389. Apple Mixer componentA sound component that is responsible for mixing together the audio data streams from all open sound channels.
  11390. Apple Sound Chip (ASC)A custom chip that, in conjunction with other circuitry, generates a stereo sound signal that drives the internal speaker or an external sound jack. Compare Enhanced Apple Sound Chip.
  11391. ASCSee Apple Sound Chip.
  11392. asynchronous sound playThe playing of sound during other, non-sound related operations. Compare synchronous sound play.
  11393. audio compressionA technique of reducing the amount of memory space required for a buffer of sampled-sound data, usually at the expense of audio fidelity. See also audio expansion.
  11394. audio componentA component that works with the Sound Manager to adjust volumes or other settings of a sound output device. Compare sound component.
  11395. audio dataSee sampled-sound data, sound, square-wave data, wave-table data.
  11396. audio decompressionSee audio expansion.
  11397. audio expansionThe decompression of compressed sound data. See also audio compression.
  11398. audio information recordA structure you can use to specify information about an audio component. Defined by the AudioInfo data type.
  11399. Audio Interchange File Format (AIFF)A sound storage file format designed to allow easy exchange of audio data among applications.
  11400. Audio Interchange File Format Extension for Compression (AIFF-C)An extension of the Audio Interchange File Format that allows for the storage of compressed sound data.
  11401. audio portAny independently-controllable sound-producing hardware connected or attached to a sound output device. A sound output device can have several audio ports.
  11402. audio selection recordA structure you can use to specify that only part of a sound be played. Defined by the AudioSelection data type.
  11403. automatic gain control (AGC)A feature of sound recording that moderates the recording to give a consistent signal level.
  11404. base frequencyThe pitch at which a sampled sound is recorded. The wave of a sampled sound may include frequencies other than the base frequency (and need not even include the base frequency).
  11405. baseline pitchSee speech pitch.
  11406. buffered expansionAudio expansion of a sound that does not occur while the sound is playing. Compare real-time expansion.
  11407. callback procedureAn application-defined procedure that is invoked at a specified time or based on specified criteria.
  11408. channelA portion of sound data that can be described by a single sound wave. Do not confuse with sound channel or speech channel. See also monophonic sound, stereo sound.
  11409. chunkAny distinct portion of a sound file.
  11410. chunk headerThe first segment of a chunk, which defines the characteristics of the chunk. Defined by the ChunkHeader data type.
  11411. codecSee compression/decompression component.
  11412. commandSee embedded speech command, sound command.
  11413. command delimiterA sequence of one or two characters that indicates the start or end of an embedded speech command.
  11414. componentA piece of code that provides a defined set of services to one or more clients. Applications, system extensions, and other components can use the services of a component. See also audio component, sound component.
  11415. component description recordA structure that contains information about a component. Defined by the ComponentDescription data type.
  11416. Component ManagerA collection of routines that allows your application or other clients to access components. The Component Manager manages components and also provides services to components.
  11417. compressed sound dataSampled-sound data that has been subjected to audio compression.
  11418. compressed sound headerA sound header that can describe noncompressed and compressed sampled-sound data, whether monophonic or stereo. Defined by the CmpSoundHeader data type. See also extended sound header, sampled sound header.
  11419. compressionSee audio compression.
  11420. compression/decompression component (codec)A component that handles data compression and decompression.
  11421. compression information recordA structure you use to specify information about a sound component that can decompress compressed audio data. Defined by the CompressionInfo data type.
  11422. computer-generated speechSee synthesized speech.
  11423. continuous play from diskSee play from disk.
  11424. continuous recordingA feature of a sound input device driver that allows recording from the device while other processing continues.
  11425. current sound input deviceThe sound input device that the user has chosen through the Sound In subpanel of the Sound control panel.
  11426. current sound output deviceThe sound output device that the user has chosen through the Sound Out subpanel of the Sound control panel.
  11427. DACSee digital-to-analog convertor.
  11428. decompressed sound dataSampled-sound data that has been subjected to audio compression and expansion.
  11429. decompressionSee audio expansion.
  11430. delimiterSee command delimiter.
  11431. delimiter information recordA structure that defines the characters used to indicate the beginning and end of a command embedded in text. Defined by the DelimiterInfo data type.
  11432. dictionarySee pronunciation dictionary.
  11433. digital signal processor (DSP)A processor that manipulates digital data.
  11434. digital-to-analog convertor (DAC)A device that converts data from digital to analog form.
  11435. double bufferingA technique used by the Sound Manager to manage a play from disk. When using this technique, the Sound Manager plays one buffer of sampled-sound data while filling a second with more data. When the first buffer of sound finishes playing, the Sound Manager plays the data in the second buffer while filling the first with more data. See also play from disk, sampled-sound data.
  11436. drop-sample conversionA form of sample rate conversion that uses an existing sample as an interpolated sample point. Compare linear interpolation.
  11437. DSPSee digital signal processor.
  11438. durationThe length of time that a sound takes to play.
  11439. EASCSee Enhanced Apple Sound Chip.
  11440. embedded speech commandIn a buffer of input text, a sequence of characters enclosed by command delimiters that provides instructions to a speech synthesizer.
  11441. ending prosodyThe rhythm, modulation, and stress patterns associated with the end of a sentence of speech.
  11442. Enhanced Apple Sound Chip (EASC)A modified Apple Sound Chip that generates stereo sound using pulse-code modulation. Compare Apple Sound Chip.
  11443. enhanced Sound ManagerAny version of the Sound Manager greater than 2.0.
  11444. error callback procedureAn application-defined procedure that is executed whenever the Speech Manager encounters an error in an embedded speech command in a buffer of input text.
  11445. expansionSee audio expansion.
  11446. extended sound headerA sound header that can describe monophonic and stereo sampled-sound data, but not compressed sound data. Defined by the ExtSoundHeader data type. See also compressed sound header, sampled sound header.
  11447. FIFOSee first-in, first-out.
  11448. Finder sound fileA file of file type 'sfil' containing a sound resource. If a user opens a Finder sound file, the Finder plays the sound resource contained within it. See also sound file, sound resource.
  11449. first-in, first-out (FIFO)Characteristic of a queue in which the first item put into the queue becomes the first item to be taken out of it. Compare last-in, first out.
  11450. frequencyThe number of times per second that an action occurs. An action’s frequency is measured in cycles per second, or hertz. See also period.
  11451. gainThe ratio of the output volume to the input volume. See also automatic gain control.
  11452. hertz (Hz)A unit of frequency, equal to one cycle per second.
  11453. instrumentA sampled sound played at varying rates to produce a number of different pitches or notes. See also voice.
  11454. interleavingThe technique of combining two or more channels of sound data by alternating small pieces of the data in each channel into a single data stream. See also sample frame.
  11455. interpolationThe process of generating sample points between two given sample points. See also linear interpolation.
  11456. kilohertz (kHz)A unit of frequency, equal to one thousand cycles per second.
  11457. last-in, first out (LIFO)Characteristic of a queue in which the last item put into the queue becomes the first item to be taken out of it. Compare first-in, first out.
  11458. LIFOSee last-in, first-out.
  11459. linear interpolationA form of interpolation that uses the calculated mean of two sample points as the interpolated sample point. Compare drop-sample conversion.
  11460. MACESee Macintosh Audio Compression and Expansion.
  11461. Macintosh Audio Compression and Expansion (MACE)A set of Sound Manager routines that allow your application to compress and expand audio data.
  11462. megahertz (MHz)A unit of frequency, equal to one million cycles per second.
  11463. microsecondA unit of time equal to one millionth of a second. Abbreviated µs.
  11464. MIDISee Musical Instrument Digital Interface.
  11465. MIDI ManagerThe part of the Macintosh system software that controls the flow of MIDI data and commands through a MIDI interface.
  11466. MIDI note valueAn integer that is defined to correspond to a frequency specified in hertz that is associated with a musical note.
  11467. millisecondA unit of time equal to one thousandth of a second. Abbreviated ms.
  11468. modulation of speechSee pitch modulation.
  11469. monophonic sound. Sound consisting of a single channel. Compare stereo sound.
  11470. multichannel soundSee stereo sound.
  11471. Musical Instrument Digital Interface (MIDI)A standard protocol for sending audio data and commands to digital devices.
  11472. noncompressed sound dataSampled-sound data that has not been subjected to audio compression or that has been decompressed.
  11473. noteSee frequency, MIDI note value.
  11474. offset-binary encodingA method of digitally encoding sound that represents the range of amplitude values as an unsigned number, with the midpoint of the range representing silence. For example, an 8-bit sound stored in offset-binary format would contain sample values ranging from 0 to 255, with a value of 128 specifying silence (no amplitude). Samples in Macintosh sound resources are stored in offset-binary form. See also two’s complement encoding.
  11475. packetA unit of compressed sampled-sound data. One or more packets make up a sample frame of compressed sampled-sound data. See also sample point.
  11476. periodThe time elapsed during one complete cycle. See also frequency.
  11477. phonemeA speech sound in a language that a speaker of the language psychologically considers to be a single unit. A single phoneme may have several allophones.
  11478. phoneme callback procedureAn application-defined procedure that is executed whenever the Speech Manager is about to pronounce a phoneme.
  11479. phoneme descriptor recordA structure that contains information about all phonemes defined for the current synthesizer. Defined by the PhonemeDescriptor data type.
  11480. phoneme information recordA structure that contains information about a phoneme. Defined by the PhonemeInfo data type.
  11481. phonemic representation of speech The representation of speech using a series of phonemes.
  11482. phonetic representation of speech The representation of speech using a series of allophones.
  11483. pitchA listener’s subjective interpretation of a sound’s frequency. See also speech pitch.
  11484. pitch modulationA fixed-point value defined on a scale from 0.000 to 100.000 that indicates the maximum amount by which the frequency of generated speech may deviate from that corresponding to the speech pitch in either direction. A value of 0.000 corresponds to a monotone.
  11485. play from diskThe ability of the Sound Manager to play sampled sounds stored on disk (either in a sound file or a sound resource) continuously without audible gaps.
  11486. playthroughA feature of sound recording that allows the user to hear, through the speaker of a Macintosh computer, the sound being recorded.
  11487. polyphonic soundSee stereo sound.
  11488. pronunciation dictionaryA list of words and their pronunciations, installed in a speech channel to override default speech synthesizer pronunciations of words.
  11489. pronunciation dictionary resourceA pronunciation dictionary stored in a resource of type 'dict'.
  11490. prosodyThe rhythm, modulation, and stress patterns of speech.
  11491. rateSee sample rate, speech rate.
  11492. real-time expansionAudio expansion of a sound that occurs while the sound is playing. Compare buffered expansion.
  11493. recordingThe process of creating an analog or digital representation of a sound. See also sampling.
  11494. sampleSee sample point.
  11495. sampled soundAny sound defined using sampled-sound data.
  11496. sampled-sound dataAny set of values that represent the sample points of a sampled sound. The values can be in either offset-binary format or two’s complement format.
  11497. sampled sound headerA sound header that can describe monophonic, noncompressed sampled-sound data. Defined by the SoundHeader data type. See also compressed sound header, extended sound header.
  11498. sample frameAn interleaved set of sample points (for noncompressed sampled-sound data) or packets (for compressed sampled-sound data).
  11499. sample pointA value representing the amplitude of sampled-sound data at a particular instant. One or more sample points make up a sample frame of noncompressed sampled-sound data. See also packet.
  11500. sample rateThe rate at which samples are recorded. Sample rates are usually measured in kilohertz or megahertz.
  11501. samplingThe process of representing a sound by measuring its amplitude at discrete points in time. See also recording.
  11502. sifterSee sound component.
  11503. soundAnything perceived by the organs of hearing. See also frequency, pitch, stereo sound, timbre.
  11504. sound channelA path that sound data traverses from an application to the sound output device. A sound channel is associated with a queue of sound commands and with other information about the audio characteristics of the sound data. See also sound channel record.
  11505. sound channel recordA structure that represents a sound channel. Defined by the SndChannel data type.
  11506. sound channel status recordA structure whose address you pass to the SndChannelStatus function. Defined by the SCStatus data type.
  11507. sound commandAn instruction to produce sound, modify sound, or otherwise assist in the overall process of sound production. See also sound command record.
  11508. sound command recordA structure that describes a sound command. Defined by the SndCommand data type.
  11509. sound componentA component that works with the Sound Manager to manipulate audio data or to communicate with a sound output device. See also audio component, compression/decompression component, sound output device component, utility component.
  11510. sound component chainA chain of sound components that links a sound source to a sound output device.
  11511. sound component data recordA structure that specifies information about the data stream generated by a sound component. Defined by the SoundComponentData data type.
  11512. sound component information selectorA value of type OSType that indicates the kind of information a sound component should return or modify.
  11513. Sound control panelA control panel that allows the user to specify basic sound-related settings and preferences. See also Alert Sounds control panel, Sound In control panel, Sound Out control panel, Volumes control panel.
  11514. sound dataSee sampled-sound data, sound, square-wave data, wave-table data.
  11515. sound double buffer header recordA structure that you use to manage your own double-buffering scheme. Defined by the SndDoubleBufferHeader and SndDoubleBufferHeader2 data types.
  11516. sound double buffer recordA structure that you use to manage your own double-buffering scheme. Defined by the SndDoubleBuffer data type.
  11517. Sound DriverA device driver on the original Macintosh computers that provided sound generation. The Sound Driver is now obsolete; it has been replaced by the Sound Manager.
  11518. sound fileA file of file type 'AIFF' or 'AIFC' that can be used to store sampled-sound data and information about that data. See also Audio Interchange File Format, Audio Interchange File Format Extension for Compression, chunk, Finder sound file, sound resource.
  11519. sound headerA data structure (usually stored in a sound resource) that contains information about a buffer of sampled-sound data. See also compressed sound header, extended sound header, sampled sound header.
  11520. Sound In control panelA subpanel of the Sound control panel that allows the user to select a sound input device. See also Alert Sounds control panel, Sound Out control panel, Volumes control panel.
  11521. sound information listA structure that specifies the information associated with a sound component information selector. Defined by the SoundInfoList data type.
  11522. sound input deviceAny hardware device (such as a microphone or audio digitizer) that records sound.
  11523. sound input device driverA standard Macintosh device driver used by the Sound Manager to manage communication between applications and a sound input device.
  11524. sound input device information selectorA variable of type OSType that is used to specify the type of information that an application or the Sound Input Manager is requesting from a sound input device driver.
  11525. Sound Input ManagerThe part of the Macintosh system software that controls the recording of sound from sound input devices.
  11526. sound input parameter blockA parameter block that contains information about sound recording. Defined by the SPB data type.
  11527. Sound ManagerThe part of the Macintosh system software that manages the production and manipulation of sounds on Macintosh computers.
  11528. Sound Manager status recordA structure filled in by the SndManagerStatus function, which gives information on the current CPU loading caused by all open channels of sound. Defined by the SMStatus data type.
  11529. Sound Out control panelA subpanel of the Sound control panel that allows the user to select a sound output device. See also Alert Sounds control panel, Sound In control panel, Volumes control panel.
  11530. sound output deviceAny hardware device (such as a speaker or sound synthesizer) that produces sound.
  11531. sound output device componentA sound component that communicates with a sound output device. See also compression/decompression component and utility component.
  11532. sound parameter blockA parameter block that describes the source data to be modified or sent to a sound output device. Defined by the SoundParamBlock data type.
  11533. sound recording dialog boxThe dialog box displayed by the Sound Input Manager when you call SndRecord or SndRecordToFile.
  11534. sound resourceA resource of resource type 'snd ' that can be use to store sound commands and sound data. See also sound file.
  11535. sound resource headerThe portion of a sound resource that describes the format of the sound resource.
  11536. sound sourceThe origin of a specific channel of sound.
  11537. sourceSee sound source.
  11538. source componentThe sound component that provides input for a particular component.
  11539. source IDA unique 4-byte identifier created by the Apple Mixer to refer to a single chain of sound components linking a sound source to the current sound output device. Defined by the SoundSource data type.
  11540. speechThe process or product of speaking. See also sound, synthesized speech.
  11541. speech amplitudeSee speech volume.
  11542. speech attributeA setting defined for a voice or a class of voices that affects the quality of speech generated by the Speech Manager. Speech attributes include speech pitch, speech rate, pitch modulation, speech volume.
  11543. speech channelThe data structure used by the Speech Manager to store settings related to speech generation. All speech must be generated through a speech channel. Defined by the SpeechChannel data type.
  11544. speech channel control flagsConstants that enable special Speech Manager features associated with speech generation.
  11545. speech commandSee embedded speech command.
  11546. speech-done callback procedureAn application-defined procedure that is executed when the Speech Manager completes speaking a buffer of input text.
  11547. speech error information recordA structure that contains information about which Speech Manager errors occurred while processing a text buffer on a given speech channel. Defined by the SpeechErrorInfo data type.
  11548. speech extension data recordA structure passed to GetSpeechInfo or SetSpeechInfo to get or set synthesizer information. Defined by the SpeechXtndData data type.
  11549. speech information selectorA variable of type OSType that is used to specify the type of information that an application or the Speech Manager is requesting from a speech synthesizer.
  11550. Speech ManagerThe part of the Macintosh system software that provides a standardized method for Macintosh applications to generate synthesized speech.
  11551. speech modulationSee pitch modulation.
  11552. speech pitchA fixed-point value on a scale from 0.000 to 100.000 that indicates the average (or baseline) frequency a speech synthesizer should use in generating synthesized speech. A value of 60.000 corresponds to Middle C on a conventional piano keyboard. See also pitch modulation.
  11553. speech rateA fixed-point value specifying the approximate number of words per minute that a speech synthesizer should use in generating speech.
  11554. speech status information recordA structure that contains information about the status of a speech channel. Defined by the SpeechStatusInfo data type.
  11555. speech synthesizerThe executable code that is linked to a speech channel and manages all communication between the Speech Manager and the Sound Manager.
  11556. speech version information recordA structure that contains information about the speech synthesizer currently being used. Defined by the SpeechVersionInfo data type.
  11557. speech volumeA fixed-point value on a scale from 0.000 to 1.000 that indicates the average amplitude a speech synthesizer should use in generating synthesized speech. A value of 0.000 corresponds to the lowest possible volume, and a value of 1.000 corresponds to the highest.
  11558. square-wave dataAny set of values that represent a sound by its frequency, amplitude, and duration.
  11559. stereo soundSound that simultaneously consists of two or more channels. Also called polyphonic sound or multichannel sound. Compare monophonic sound.
  11560. synchronization callback procedureAn application-defined procedure that is executed whenever the Speech Manager encounters an embedded synchronization speech command in a buffer of input text.
  11561. synchronous sound playA playing of sound by the Sound Manager that prevents other code from executing until the sound is done playing. Compare asynchronous sound play.
  11562. synthesized speechThe product of converting nonaural tokens (such as written or digitally-stored words or phonemes) into speech. See also Speech Manager.
  11563. synthesizerSee speech synthesizer.
  11564. system alert soundA sound resource stored in the System file that is played whenever an application or other executable code calls the SysBeep procedure.
  11565. text The written representation of language.
  11566. text-done callback procedureAn application-defined procedure that is executed when the Speech Manager has finished processing (although not necessarily speaking) a buffer of input text.
  11567. text-to-speechSee synthesized speech.
  11568. tickA unit of time equal to one sixtieth of a second.
  11569. timbreThe tone of a sound, which can range from clear to buzzing.
  11570. two’s complement encodingA system for digitally encoding sound that stores the amplitude values as a signed number—silence is represented by a sample with a value of 0. For example, with 8-bit sound samples, two’s complement values would range from –128 to 127, with 0 meaning silence. The Audio Interchange File Format (AIFF) used by the Sound Manager stores samples in two’s complement form. Compare offset-binary encoding.
  11571. uncompressed sound dataSee decompressed sound data, noncompressed sound data.
  11572. utility componentA sound component that performs some modification on sound data and does not communicate directly with any sound output device. See also sound component, sound output device component.
  11573. version recordA structure that contains version information. Defined by the NumVersion data type.
  11574. voice(1) The set of parameters that specify a particular quality of synthesized speech. A voice is designed to work with a particular speech synthesizer. (2) A sampled sound played at varying rates to produce a number of different pitches or notes. See also instrument.
  11575. voice description recordA structure that contains information about a voice. Defined by the VoiceDescription data type.
  11576. voice file information recordA structure that contains information about the file in which a voice is stored and the resource ID of the voice within that file. Defined by the VoiceFileInfo data type.
  11577. voice specification recordA structure that provides a unique specification that you must use to obtain information about a voice. Defined by the VoiceSpec data type.
  11578. volumeSee amplitude, speech volume.
  11579. Volumes control panelA subpanel of the Sound control panel that allows the user to select volumes. See also Alert Sounds control panel, Sound In control panel, Sound Out control panel.
  11580. VOX recordingA feature that allows sound recording only when the sound to be recorded exceeds a certain amplitude.
  11581. VOX stoppingA feature that stops sound recording when the sound falls below a certain amplitude.
  11582. wave amplitudeThe height of a sound wave at an instant of time. Compare amplitude.
  11583. waveformThe shape of a wave (a graph of a wave’s amplitude over time).
  11584. wavelengthThe extent of one complete cycle of a wave.
  11585. wave tableA sequence of wave amplitudes measured at fixed intervals.
  11586. wave-table dataAny set of values that represent a sound by a wave table.
  11587. word callback procedureAn application-defined procedure that is executed whenever the Speech Manager is about to speak a word.
  11588. Index
  11589.  
  11590.  
  11591. A
  11592.  
  11593. A5 register
  11594. and Sound Manager callback procedures2-48
  11595. and Speech Manager callback procedures4-20 to 4-21, 4-82
  11596. abbreviation entries4-92
  11597. action flags5-27
  11598. 'adio' resource type6-5
  11599. AGC. See automatic gain control
  11600. AIFF-C files
  11601. and AIFF files1-19
  11602. creating1-41
  11603. defined1-18 to 1-20
  11604. file type of2-87
  11605. and Finder sound files1-19
  11606. format of2-87 to 2-89
  11607. playing sounds in1-19, 1-26
  11608. recording sounds to1-31
  11609. sample frames in2-89
  11610. sample of2-88
  11611. specifications of2-82 to 2-89
  11612. storing sounds in1-40 to 1-41, 2-9, 3-30
  11613. AIFF files
  11614. and AIFF-C files1-19
  11615. creating1-41
  11616. defined1-18 to 1-20
  11617. file type of2-66, 2-87
  11618. and Finder sound files1-19
  11619. format of2-81 to 2-89
  11620. playing sounds in1-19, 1-26
  11621. recording sounds to1-31
  11622. sample frames in2-89
  11623. specifications of2-82, 2-89
  11624. storing sounds in1-40 to 1-41, 2-9, 3-30
  11625. alert sounds. See system alert sounds
  11626. Alert Sounds control panel1-16, 1-24, 5-24
  11627. allophones4-33
  11628. ampCmd command2-27, 2-96
  11629. amplitude of sounds2-8, 2-27
  11630. amplitude of speech. See speech volume
  11631. Annotation Chunks2-82
  11632. Apple Mixer. See Apple Mixer component
  11633. Apple Mixer component
  11634. closing5-34 to 5-35
  11635. introduced1-13 to 1-14, 5-6 to 5-7
  11636. opening5-33 to 5-34
  11637. Apple Sound Chip (ASC)1-10, 2-36
  11638. Application Specific Chunks2-82
  11639. ASC. See Apple Sound Chip
  11640. asynchronous sound play2-46 to 2-56, 2-62
  11641. audio components6-3 to 6-17
  11642. See also sound components
  11643. creating6-5 to 6-7
  11644. data structures for6-8 to 6-9
  11645. defined6-3
  11646. getting information about6-14
  11647. getting mute states6-11 to 6-12
  11648. getting volumes6-10
  11649. opening resource files6-8
  11650. resetting6-13
  11651. routines defined by6-9 to 6-14
  11652. run-time environment6-8
  11653. selectors6-7 to 6-8
  11654. setting mute states6-12 to 6-13
  11655. setting volumes6-11
  11656. subtypes of6-6
  11657. types of6-6
  11658. writing6-5 to 6-8
  11659. audio compression
  11660. determining type of5-23
  11661. formats for storage1-18
  11662. introduced1-5, 1-7 to 1-8
  11663. using MACE routines2-14 to 2-17, 2-66 to 2-68, 2-142 to 2-145
  11664. and versions of the Sound Manager1-14
  11665. audio data
  11666. See also sampled-sound data, sounds, square-wave data, wave-table data
  11667. getting from the source component5-40
  11668. mixing5-6 to 5-7
  11669. setting the output data type5-41 to 5-42
  11670. types of5-26
  11671. audio decompression. See audio expansion
  11672. audio expansion
  11673. and audio codecs1-7
  11674. introduced1-5
  11675. using MACE routines2-14 to 2-17, 2-66 to 2-68, 2-142 to 2-147
  11676. and versions of the Sound Manager1-14
  11677. AudioGetInfo function6-14
  11678. AudioGetMute function6-11 to 6-12
  11679. AudioGetVolume function6-10
  11680. AudioInfo data type6-9
  11681. audio information records6-9
  11682. Audio Interchange File Format (AIFF). See AIFF files
  11683. Audio Interchange File Format for Compression (AIFF-C). See AIFF-C files
  11684. audio ports6-3 to 6-5
  11685. Audio Recording Chunks2-82
  11686. AudioSelection data type2-53, 2-100
  11687. audio selection records2-53, 2-100
  11688. AudioSetMute function6-12 to 6-13
  11689. AudioSetToDefaults function6-13
  11690. AudioSetVolume function6-11
  11691. AudioVision 14 Display6-3 to 6-5, 6-6
  11692. Author Chunks2-82
  11693. automatic gain control
  11694. defined3-4
  11695. status of3-20
  11696. availableCmd command2-95
  11697. B
  11698.  
  11699. base frequencies2-105, 2-107
  11700. baseline pitch. See speech pitch
  11701. baseline pitch embedded speech command4-27
  11702. bilingual speech1-22, 4-9
  11703. BlockMove procedure, using in doubleback procedures2-72
  11704. bufferCmd command
  11705. described2-97
  11706. examples of use2-57, 2-61 to 2-62
  11707. using for compressed sound samples2-61, 2-62
  11708. buffered expansion2-15
  11709. buffers. See double buffers
  11710. bundle bit5-11, 6-7
  11711. busy loops, creating4-14
  11712. byte recording values, converting to milliseconds3-52
  11713. C
  11714.  
  11715. callBackCmd command
  11716. described2-94
  11717. example of use2-48
  11718. using to synchronize sound with other actions2-51
  11719. callback procedures
  11720. defined4-19
  11721. installing2-48
  11722. and Sound Manager2-46 to 2-51, 2-152 to 2-153
  11723. and Speech Manager4-10, 4-19 to 4-23, 4-82 to 4-89
  11724. channels. See sound channels, speech channels
  11725. character mode embedded speech command4-26
  11726. char embedded speech command selector4-26
  11727. ChunkHeader data type2-83, 2-113
  11728. chunk header record2-83
  11729. chunk headers2-113
  11730. chunks (in AIFF and AIFF-C files)
  11731. Annotation2-82
  11732. Application Specific2-82
  11733. Audio Recording2-82
  11734. Author2-82
  11735. Comments2-82
  11736. Common2-82, 2-85 to 2-87, 2-115 to 2-117
  11737. Copyright2-82
  11738. data types used to describe2-83
  11739. defined2-81
  11740. determining size of2-64
  11741. Extended Common Chunks2-85, 2-115 to 2-117
  11742. finding2-62 to 2-66
  11743. Form2-82, 2-83 to 2-84, 2-113 to 2-114
  11744. Format Version2-82, 2-84 to 2-85, 2-114
  11745. IDs for2-98 to 2-99
  11746. Instrument2-82
  11747. list of types2-82
  11748. local2-84, 2-114
  11749. Marker2-82
  11750. MIDI Data2-82
  11751. modifying2-88
  11752. Name2-82
  11753. order of2-88
  11754. Sound Accelerator2-82
  11755. Sound Data2-82, 2-87, 2-117 to 2-118
  11756. structure of2-82 to 2-83
  11757. CloseMixerSoundComponent function5-34 to 5-35
  11758. cmnt embedded speech command selector4-26
  11759. CmpSoundHeader data type2-108 to 2-111
  11760. codecs. See compression/decompression components
  11761. command delimiters
  11762. changing with an embedded speech command4-26
  11763. changing with a speech information selector4-40
  11764. default4-23, 4-40, 4-54
  11765. defined4-23, 4-26
  11766. specification of4-54
  11767. commands. See embedded speech commands, sound commands
  11768. comment embedded speech command4-26
  11769. Comments Chunks2-82
  11770. CommonChunk data type2-85, 2-115
  11771. Common Chunks2-82, 2-85 to 2-87, 2-115
  11772. Comp3to1 procedure2-66, 2-143 to 2-144
  11773. Comp6to1 procedure2-66, 2-144 to 2-145
  11774. completion routines
  11775. and Sound Input Manager3-9, 3-54 to 3-55
  11776. and Sound Manager2-47, 2-52, 2-151 to 2-152
  11777. ComponentDescription data type5-10, 6-6
  11778. Component Manager
  11779. and audio components6-3
  11780. and sound components5-3
  11781. and Speech Manager1-20, 4-5
  11782. ComponentResource data type5-9 to 5-11, 6-5 to 6-7
  11783. components. See audio components, sound components
  11784. component selectors5-12 to 5-14, 6-7 to 6-8
  11785. compressed sound header records2-108 to 2-111
  11786. compression. See audio compression
  11787. compression/decompression components (codecs)1-7, 1-14 to 1-15, 5-3, 5-6, 5-30
  11788. compression IDs2-110
  11789. CompressionInfo data type5-32
  11790. compression information records5-32
  11791. compression types2-86, 2-116, 2-117
  11792. computer-generated speech. See Speech Manager
  11793. ContainerChunk data type2-84, 2-114
  11794. container chunks. See Form Chunks
  11795. ContinueSpeech function
  11796. described4-62 to 4-63
  11797. minimizing latency of speech generation with4-52, 4-59
  11798. continuing paused speech4-18, 4-62 to 4-63
  11799. continuous play from disk. See play-from-disk routines
  11800. continuous recording
  11801. defined3-5
  11802. supporting3-17
  11803. continuous speech4-51, 4-58
  11804. Control calls3-5, 3-13 to 3-15
  11805. Copyright Chunks2-82
  11806. CountVoices function4-64 to 4-65
  11807. CPU loading values2-40
  11808. cultural values, associated with sounds1-24
  11809. current sound input device1-16
  11810. current sound output device1-10
  11811. D
  11812.  
  11813. DAC. See digital-to-analog convertor
  11814. data. See also audio data
  11815. sampled-sound2-9 to 2-11
  11816. square-wave2-7 to 2-8
  11817. wave-table2-8
  11818. data format flags5-28 to 5-29
  11819. data offset bit in sound commands2-75
  11820. decompression. See audio expansion
  11821. delimiter. See command delimiter
  11822. delimiter embedded speech command4-26
  11823. DelimiterInfo data type4-54
  11824. delimiter information records4-54
  11825. Device Manager, and sound input device drivers3-13 to 3-17
  11826. 'dict' atom type4-91
  11827. dictionaries. See pronunciation dictionaries
  11828. Dictionary Manager4-37
  11829. 'dict' resource type4-36, 4-89 to 4-93
  11830. digital signal processor (DSP)1-6, 1-8, 1-10, 5-5
  11831. digital-to-analog converter (DAC)1-9
  11832. DisposeSpeechChannel function4-70 to 4-71
  11833. dlim embedded speech command selector4-26
  11834. document annotations, audio1-24
  11835. documents, and Speech Manager callback procedures4-20
  11836. doubleback procedures
  11837. defined2-72 to 2-73, 2-153 to 2-154
  11838. limitations of2-72
  11839. and sound double buffer header records2-112
  11840. syntax of2-72
  11841. writing2-72 to 2-73
  11842. double buffering1-19
  11843. double buffers2-68 to 2-73
  11844. managing2-147 to 2-148
  11845. setting up2-70 to 2-72
  11846. drop-sample conversion2-92
  11847. DSP. See digital signal processor
  11848. duration of sounds2-7, 3-6
  11849. E
  11850.  
  11851. EASC. See Enhanced Apple Sound Chip
  11852. Edit menu commands, and alert sounds list1-16
  11853. embedded speech commands4-23 to 4-30
  11854. changing delimiters temporarily4-54
  11855. deemphasizing words4-32
  11856. defined4-23
  11857. emphasizing words4-31
  11858. errors for4-30
  11859. examples of use4-30 to 4-32
  11860. format of parameters4-24
  11861. hexadecimal numbers in4-24
  11862. list of4-26 to 4-29
  11863. obtaining errors involving4-20
  11864. raising the speech pitch4-32
  11865. specifying relative values4-24
  11866. synchronization messages in4-20
  11867. syntax of4-24 to 4-30
  11868. writing comments in4-26
  11869. emphasis embedded speech command4-26
  11870. emph embedded speech command selector4-26
  11871. emptyCmd command2-30
  11872. ending prosody
  11873. defined4-9
  11874. disabling4-51, 4-58
  11875. Enhanced Apple Sound Chip (EASC)1-10
  11876. enhanced Sound Manager1-14
  11877. entry types4-92
  11878. error callback procedures4-19 to 4-20, 4-86 to 4-87
  11879. Exp1to3 procedure2-66, 2-145 to 2-146
  11880. Exp1to6 procedure2-66, 2-146 to 2-147
  11881. expanding sounds2-145 to 2-147
  11882. expansion. See audio expansion
  11883. ExtCommonChunk data type2-85, 2-116
  11884. Extended Common Chunks2-85, 2-115 to 2-117
  11885. extended sound header records2-106 to 2-108
  11886. extended sound headers2-106 to 2-108
  11887. extensions, installing sound input device drivers from3-13
  11888. ExtSoundHeader data type2-106
  11889. F
  11890.  
  11891. file types
  11892. 'AIFC'. See AIFF-C files
  11893. 'AIFF'. See AIFF files
  11894. 'sfil'1-19
  11895. Finder sound files1-19, 1-23
  11896. flushCmd command
  11897. described2-94
  11898. sent by SndDisposeChannel function2-24, 2-130
  11899. using to flush sound channels2-29
  11900. format 1 'snd ' resources1-18, 2-74, 2-75 to 2-80
  11901. format 2 'snd ' resources1-18, 2-74, 2-80 to 2-81
  11902. FormatVersionChunk data type2-84, 2-114
  11903. Format Version Chunks2-82, 2-84 to 2-85, 2-114
  11904. format version embedded speech command4-29
  11905. Form Chunks2-82, 2-83 to 2-84, 2-113 to 2-114
  11906. frames of sampled sound2-10
  11907. freqCmd command
  11908. calculating proper playback rate for2-105
  11909. compared to freqDurationCmd2-41
  11910. described2-96
  11911. freqDurationCmd command
  11912. calculating proper playback rate for2-105
  11913. compared to freqCmd2-41
  11914. described2-95
  11915. using to play frequencies2-41
  11916. frequencies
  11917. as MIDI note values2-42, 4-7
  11918. defined2-7
  11919. distinguished from speech pitches4-8
  11920. playing2-41 to 2-46
  11921. playing for indefinite duration2-41
  11922. G
  11923.  
  11924. gain3-20
  11925. Gestalt function
  11926. and Sound Input Manager1-27 to 1-28, 3-13, 3-17 to 3-18
  11927. and Sound Manager1-15, 2-33 to 2-34, 2-35 to 2-37, 2-90 to 2-91
  11928. and Speech Manager1-31 to 1-32, 4-12 to 4-13
  11929. getAmpCmd command2-28, 2-96
  11930. GetDefaultOutputVolume function2-32, 2-141 to 2-142
  11931. GetIndVoice function4-65 to 4-66
  11932. getRateCmd command2-26, 2-97
  11933. GetSoundHeaderOffset function2-138 to 2-139
  11934. GetSoundPreference function5-36
  11935. GetSpeechInfo function4-77 to 4-78
  11936. GetSpeechPitch function4-7, 4-75 to 4-76
  11937. GetSpeechRate function4-73 to 4-74
  11938. GetSysBeepVolume function2-32, 2-140
  11939. GetVoiceDescription function4-66 to 4-67
  11940. GetVoiceInfo function4-67 to 4-68
  11941. getVolumeCmd command2-31, 2-96
  11942. H
  11943.  
  11944. hertz2-16, 4-7
  11945. hexadecimal numbers, in embedded speech commands4-24
  11946. hissing sound, eliminating during real-time expansion2-17
  11947. human interface guidelines. See user interface guidelines
  11948. HyperCard, and format 2 'snd ' resources2-74
  11949. I
  11950.  
  11951. 'ICON' resource type5-9, 6-6
  11952. initialization parameters, for sound channels2-22 to 2-23, 2-91 to 2-92
  11953. inpt embedded speech command selector4-27
  11954. input mode embedded speech command4-27
  11955. Instrument Chunks2-82
  11956. instruments, installing into sound channels2-10
  11957. interleaving of sample points or packets2-10
  11958. interpolation. See linear interpolation
  11959. interrupt routines, of Sound Input Manager3-10, 3-55 to 3-56
  11960. interrupt time
  11961. Sound Input Manager completion routines at3-55
  11962. Sound Manager callback procedures at2-49, 2-153
  11963. Sound Manager completion routines at2-152
  11964. Sound Manager doubleback procedures at2-72, 2-154
  11965. sound recording at3-16
  11966. Speech Manager callback procedures at4-20, 4-82
  11967. IODone function, and sound input device drivers3-16
  11968. J
  11969.  
  11970. JIODone global jump vector, and sound input device drivers3-16
  11971. K
  11972.  
  11973. kPreflightThenPause flag bit4-52, 4-59
  11974. kUseOptionalOutputDevice constant2-128
  11975. L
  11976.  
  11977. LeftOverBlock data type2-119
  11978. leftover blocks2-119
  11979. lexical stress symbols4-34
  11980. linear interpolation2-24, 2-92
  11981. loadCmd command2-95
  11982. local chunks2-84
  11983. localization, sounds and1-24
  11984. looping sounds2-45 to 2-46
  11985. M
  11986.  
  11987. MACE2-14 to 2-17, 2-66
  11988. testing for version2-133 to 2-134
  11989. MACEVersion function2-35, 2-133 to 2-134
  11990. Macintosh Audio Compression and Expansion (MACE). See MACE
  11991. MakeVoiceSpec function4-64
  11992. Marker Chunks2-82
  11993. menu bar, blinking of2-41
  11994. MIDI (Musical Instrument Digital Interface)1-6
  11995. MIDI Data Chunks2-82
  11996. MIDI Manager1-6
  11997. MIDI note values4-7
  11998. converting to hertz values2-43
  11999. defined2-7
  12000. introduced2-42
  12001. table of2-43
  12002. millisecond recording values, converting to bytes3-51 to 3-52
  12003. modifiers2-149 to 2-151
  12004. modulation of speech. See pitch modulation
  12005. 'movr' creator type1-19
  12006. multichannel sound. See stereo sound
  12007. multilingual speech1-22, 4-9
  12008. Musical Instrument Digital Interface. See MIDI
  12009. N
  12010.  
  12011. Name Chunks2-82
  12012. NewSpeechChannel function4-69 to 4-70
  12013. nmbr embedded speech command selector4-27
  12014. notes. See frequencies, MIDI note values
  12015. NuBus expansion cards, for audio hardware enhancement1-10
  12016. nullCmd command2-94
  12017. number mode embedded speech command4-27
  12018. NumVersion data type2-118
  12019. O
  12020.  
  12021. offset-binary encoding2-11
  12022. OpenMixerSoundComponent function5-7, 5-33 to 5-34
  12023. output rate2-16
  12024. P
  12025.  
  12026. packets2-11, 2-67
  12027. pad bytes, in AIFF and AIFF-C files2-87
  12028. param2 field2-75
  12029. pauseCmd command2-29, 2-94
  12030. PauseSpeechAt function4-61 to 4-62
  12031. pausing speech4-18 to 4-19, 4-61 to 4-62
  12032. pbas embedded speech command selector4-27
  12033. phoneme callback procedures4-87 to 4-88
  12034. PhonemeDescriptor data type4-53
  12035. phoneme descriptor records4-53
  12036. PhonemeInfo data type4-52
  12037. phoneme information records4-52 to 4-53
  12038. phonemes
  12039. conversion from text4-32, 4-79 to 4-80
  12040. getting information about4-34
  12041. lengthening duration of4-35
  12042. shortening duration of4-35
  12043. symbols for4-33 to 4-34
  12044. phonemic representation of speech4-32 to 4-34
  12045. pitch
  12046. changing2-10
  12047. defined2-7
  12048. pitch modulation
  12049. allowable range4-8
  12050. defined4-8
  12051. valid ranges of4-9
  12052. pitch modulation embedded speech command4-28
  12053. play-from-disk routines
  12054. introduced1-19
  12055. testing for availability of2-35 to 2-37
  12056. playing frequencies2-41 to 2-46
  12057. choosing a data type2-41
  12058. of indefinite duration2-41
  12059. playing sampled sounds
  12060. at arbitrary frequencies2-43
  12061. with bufferCmd2-61 to 2-62
  12062. playing selections of sound2-53
  12063. playthrough feature3-5
  12064. pmod embedded speech command selector4-28
  12065. polyphonic sound. See stereo sound
  12066. preconfiguring sound channels2-131, 2-132
  12067. preferences
  12068. restoring5-36
  12069. storing5-35 to 5-36
  12070. pronunciation dictionaries4-36 to 4-39, 4-89 to 4-93
  12071. creating temporary dictionaries4-36
  12072. defined4-36
  12073. and Dictionary Manager4-37
  12074. entries4-37 to 4-39
  12075. entry codes4-92
  12076. example of4-38
  12077. field type codes4-93
  12078. format of4-89 to 4-93
  12079. format version4-91
  12080. installing4-37, 4-80 to 4-82
  12081. order of entries4-38
  12082. resource headers4-39, 4-91
  12083. resources4-36 to 4-39, 4-89 to 4-93
  12084. storing in a file’s data fork4-90
  12085. uses of4-37
  12086. using alternative storage formats4-90
  12087. pronunciation entries4-92
  12088. prosodic control symbols4-34 to 4-36
  12089. prosody4-9, 4-34 to 4-36
  12090. punctuation marks, effect on prosody4-35 to 4-36
  12091. Q
  12092.  
  12093. quietCmd command2-94
  12094. sent by SndDisposeChannel function2-24, 2-130
  12095. using with freqDurationCmd2-41
  12096. R
  12097.  
  12098. rate. See sample rate, speech rate
  12099. rateCmd command2-26, 2-97
  12100. rate embedded speech command selector4-28
  12101. Read calls3-5, 3-13 to 3-16
  12102. real-time expansion2-15, 2-17
  12103. recording sounds3-6 to 3-9
  12104. described1-28 to 1-31, 1-38 to 1-41, 3-28 to 3-30
  12105. directly from device3-6 to 3-9, 3-33 to 3-38
  12106. effect of interruption on sound input device driver3-15
  12107. in stereo3-16
  12108. introduced1-15 to 1-17
  12109. specifying duration3-6
  12110. without standard interface3-4
  12111. reInitCmd command2-23, 2-94
  12112. ReleaseResource function, and sound resources2-25
  12113. request parameter blocks, passed to sound input device drivers3-13
  12114. reset embedded speech command4-28
  12115. ResourceSpec data type5-9
  12116. resource types
  12117. 'adio'6-5
  12118. 'dict'4-36, 4-89 to 4-93
  12119. 'ICON'5-9, 6-6
  12120. 'sift'5-9
  12121. 'snd '. See 'snd ' resource type, sound resources
  12122. 'STR '5-9, 6-6
  12123. 'thng'5-8 to 5-11, 6-5 to 6-7
  12124. 'ttsd'4-91
  12125. 'vers'2-35, 2-118
  12126. restCmd command2-96
  12127. resumeCmd command2-29, 2-94
  12128. resuming speech4-62 to 4-63
  12129. rset embedded speech command selector4-28
  12130. S
  12131.  
  12132. sample. See sample point
  12133. sampled-sound data2-9 to 2-11
  12134. computing length of2-46
  12135. format of2-10 to 2-11
  12136. modifying during recording3-55 to 3-56
  12137. obtaining data without header information3-4
  12138. packet sizes for compressed data2-67
  12139. setting up header information for3-4
  12140. sampled sounds. See also sounds
  12141. changing frequency of2-26
  12142. compressing. See compressing sounds
  12143. disk space requirements for2-14
  12144. expanding. See expanding sounds
  12145. input buffer size3-6
  12146. installing as voices in channels2-44
  12147. introduced2-9 to 2-11
  12148. multiple channels of1-13 to 1-14, 2-14
  12149. number of commands used in2-21
  12150. output buffer size required2-66 to 2-67
  12151. pausing2-27
  12152. playing
  12153. asynchronously2-46, 2-50, 2-52 to 2-53
  12154. continuously2-45 to 2-46
  12155. play from disk1-18 to 1-20, 1-26 to 1-27, 2-52 to 2-53
  12156. selections of2-53
  12157. using low-level routines2-61 to 2-62
  12158. recording1-15 to 1-17
  12159. storing1-18 to 1-20, 2-9, 3-44 to 3-46
  12160. synchronizing2-31
  12161. sample frames2-10
  12162. sample points2-10 to 2-11
  12163. sample rates2-16, 2-97, 2-105, 2-107, 2-109
  12164. sample routines
  12165. MyAdjustSpeechAttributes4-16 to 4-17
  12166. MyAudioDispatch6-7
  12167. MyCallback2-48
  12168. MyCanPlayMultiChannels2-36
  12169. MyChannelIsPaused2-39
  12170. MyCheckSndChan2-49
  12171. MyCleanUpTrackedChan2-55 to 2-56
  12172. MyCompressBy32-67
  12173. MyCreateSndChannel2-20
  12174. MyDBSndPlay2-70 to 2-72
  12175. MyDisposeSndChannel2-25
  12176. MyDoLoopEntireSound2-45
  12177. MyDoubleBackProc2-73
  12178. MyFindChunk2-63 to 2-64
  12179. MyGetChunkData2-65
  12180. MyGetComponentRoutine5-14 to 5-16
  12181. MyGetDeviceName3-12
  12182. MyGetDeviceSettings3-12
  12183. MyGetNumChannels2-40
  12184. MyGetSoundHeader2-60
  12185. MyGetSoundHeaderOffset2-58 to 2-59
  12186. MyHalveFreq2-26
  12187. MyHasEnhancedSoundManager2-35
  12188. MyHasPlayFromDisk2-37
  12189. MyHasSoundInput1-27
  12190. MyHasSpeech1-32
  12191. MyHasStereo2-34
  12192. MyInstallBoysVoice4-15
  12193. MyInstallCallback2-48
  12194. MyInstallSampledVoice2-44
  12195. MyInstallWordCallback4-21 to 4-22
  12196. MyLowLevelSampledSndPlay2-62
  12197. MyPauseAndContinueSpeech4-18 to 4-19
  12198. MyPlayFrequencyOnce2-42
  12199. MyPlaySampledSound2-57
  12200. MyPlaySndResource1-26
  12201. MyPlaySoundFile1-27
  12202. MyRecordSnd3-7 to 3-8
  12203. MyRecordSndResource1-29 to 1-30
  12204. MyRecordSoundFile1-31
  12205. MyRecordThruDialog1-28
  12206. MySetAmplitude2-27
  12207. MySetTrackChanDispose2-55
  12208. MySetupCallbacks4-21
  12209. MySetVolume2-32
  12210. MySoundCompletionRoutine2-52
  12211. MySoundComponentGetInfo5-19 to 5-21
  12212. MySoundComponentInitOutputDevice5-17
  12213. MySpeakStringResource1-32
  12214. MySpeakStringResourceSync1-33
  12215. MySpeechMgrPresent4-12 to 4-13
  12216. MyStartPlaying2-50
  12217. MyStopPlaying2-50
  12218. MyStopSpeech1-34
  12219. MySurfDispatch5-12 to 5-14
  12220. MySync1Chan2-30
  12221. MyUseDictionary4-37 to 4-38
  12222. MyUseSpeechChannel4-13 to 4-14
  12223. MyWordCallback4-22
  12224. Scrapbook, representation of sounds in1-23
  12225. SCStatus data type2-38, 2-101
  12226. SetDefaultOutputVolume function2-32, 2-142
  12227. SetSoundPreference function5-35 to 5-36
  12228. SetSpeechInfo function4-78 to 4-79
  12229. SetSpeechPitch function4-76
  12230. SetSpeechRate function4-74 to 4-75
  12231. SetSysBeepVolume function2-32, 2-140 to 2-141
  12232. SetupAIFFHeader function3-46 to 3-48
  12233. SetupSndHeader function3-9, 3-44 to 3-46
  12234. 'sfil' file type1-19
  12235. sifters. See sound components
  12236. 'sift' resource type5-9
  12237. silence embedded speech command4-28
  12238. Simple Beep1-25, 2-76 to 2-77
  12239. slnc embedded speech command selector4-28
  12240. SMStatus data type2-39, 2-102
  12241. SndAddModifier function2-150 to 2-151, 5-4
  12242. SndChannel data type2-13, 2-103 to 2-104
  12243. SndChannelStatus function2-37, 2-46, 2-135 to 2-136
  12244. SndCommand data type2-12, 2-99 to 2-100
  12245. SndControl function2-134 to 2-135
  12246. SndDisposeChannel function2-129 to 2-130
  12247. introduced2-24
  12248. and quietCmd2-29
  12249. SndDoCommand function2-130 to 2-131
  12250. introduced2-12
  12251. and other low-level routines2-17
  12252. SndDoImmediate function2-131 to 2-132
  12253. introduced2-12
  12254. issuing flushCmd with2-29
  12255. issuing quietCmd with2-28
  12256. and other low-level routines2-17
  12257. SndDoubleBuffer data type2-69, 2-112
  12258. SndDoubleBufferHeader2 data type2-111
  12259. SndDoubleBufferHeader data type2-69, 2-111
  12260. SndGetSysBeepState procedure2-137
  12261. SndManagerStatus function
  12262. described2-136 to 2-137
  12263. example of use2-40
  12264. introduced2-39
  12265. SndNewChannel function
  12266. described2-127 to 2-129
  12267. examples of use2-20 to 2-22
  12268. introduced2-14
  12269. specifying an initialization parameter2-22
  12270. SndPauseFilePlay function2-53, 2-125 to 2-126
  12271. SndPlayDoubleBuffer function2-68, 2-147 to 2-148
  12272. SndPlay function
  12273. described1-35 to 1-36, 2-121 to 2-122
  12274. examples of use1-25, 3-9
  12275. playing compressed sound resources with2-15, 2-66
  12276. using to play Finder sound files1-19
  12277. SndRecord function
  12278. described1-39 to 1-40, 3-28 to 3-29
  12279. example use of1-28 to 1-29
  12280. introduced1-17
  12281. SndRecordToFile function
  12282. described1-40 to 1-41, 3-30
  12283. introduced1-17
  12284. 'snd ' resource type. See also sound resources
  12285. alternatives to2-9
  12286. format 11-18, 2-74, 2-75 to 2-80, 3-45
  12287. format 21-18, 2-74, 2-80 to 2-81
  12288. introduced1-16, 1-17 to 1-18
  12289. structure of2-154 to 2-156
  12290. SndSetSysBeepState function2-137 to 2-138
  12291. SndSoundManagerVersion function2-35, 2-133
  12292. SndStartFilePlay function
  12293. default buffer allocation1-27
  12294. described1-36 to 1-38, 2-123 to 2-125
  12295. using to play sound files1-19, 1-27
  12296. SndStopFilePlay function2-53, 2-126 to 2-127
  12297. Sony sound chip1-9
  12298. Sound Accelerator Chunks2-82
  12299. sound channel records2-25, 2-103 to 2-104
  12300. sound channels
  12301. allocating2-20 to 2-22, 2-127
  12302. bypassing1-12, 2-12
  12303. determining number allocated2-40
  12304. executing callback procedures2-94
  12305. flushing2-28 to 2-29, 2-94
  12306. getting information about all channels2-39 to 2-40, 2-136 to 2-137
  12307. getting information about a single channel2-37 to 2-39, 2-135 to 2-136
  12308. initializing2-22 to 2-24
  12309. installing voices into2-43 to 2-45
  12310. introduced1-11, 2-13 to 2-14
  12311. linking modifiers to2-150
  12312. multiple1-13 to 1-14, 2-14, 2-53 to 2-56
  12313. pausing2-29 to 2-30, 2-94
  12314. playing notes in2-95, 2-96
  12315. preconfiguring2-97, 2-131, 2-132
  12316. reducing memory requirements of2-21
  12317. reinitializing2-23, 2-94
  12318. releasing2-24 to 2-25, 2-129 to 2-130
  12319. restarting2-29 to 2-30, 2-94
  12320. resting2-96
  12321. sample rate of2-97
  12322. sending commands2-130 to 2-132
  12323. setting timbre of2-96
  12324. setting volume of2-96
  12325. specifying length of2-21
  12326. stopping2-28 to 2-29, 2-94, 2-125 to 2-127
  12327. synchronizing2-30 to 2-31, 2-95
  12328. testing for multichannel sound capability2-35 to 2-37
  12329. using low-level routines2-62
  12330. sound channel status records2-38, 2-101 to 2-102
  12331. soundCmd command2-44, 2-97
  12332. sound command records2-99 to 2-100
  12333. sound commands
  12334. data offset bit2-75
  12335. in sound resources2-155
  12336. introduced1-11, 2-11 to 2-13
  12337. issuing2-12, 2-130
  12338. list of constants for2-12 to 2-13, 2-93 to 2-97
  12339. number per channel2-21
  12340. referencing sampled-sound data2-60
  12341. structure of2-12
  12342. SoundComponentAddSource function5-42 to 5-43
  12343. sound component chains1-8 to 1-9, 5-4 to 5-5
  12344. SoundComponentData data type5-8, 5-29 to 5-30
  12345. sound component data records5-8, 5-29 to 5-30
  12346. sound component features flags5-26 to 5-27
  12347. SoundComponentGetInfo function5-18 to 5-21, 5-22 to 5-26, 5-44 to 5-45
  12348. SoundComponentGetSourceData function5-40
  12349. SoundComponentGetSource function5-39 to 5-40
  12350. sound component information selectors5-18, 5-22 to 5-26
  12351. SoundComponentInitOutputDevice function5-37 to 5-38
  12352. SoundComponentPauseSource function5-48
  12353. SoundComponentPlaySourceBuffer function5-27, 5-49
  12354. SoundComponentRemoveSource function5-43 to 5-44
  12355. sound components5-3 to 5-57
  12356. See also audio components
  12357. constants for5-22 to 5-29
  12358. creating5-8 to 5-11
  12359. data structures for5-29 to 5-32, ?? to 5-32
  12360. defined1-7 to 1-9, 5-4
  12361. getting information about5-18 to 5-21, 5-22 to 5-26, 5-31, 5-44 to 5-45
  12362. information selectors5-18, 5-22 to 5-26
  12363. opening5-16 to 5-18
  12364. opening resource files5-16
  12365. registering5-16 to 5-17
  12366. restoring preferences5-36
  12367. routines defined by5-36 to 5-49
  12368. run-time environment5-16
  12369. setting information about5-18, 5-22 to 5-26, 5-31, 5-45 to 5-46
  12370. storing preferences5-35 to 5-36
  12371. subtypes of5-10
  12372. types of5-10
  12373. writing5-8 to 5-21
  12374. SoundComponentSetInfo function5-23 to 5-26, 5-45 to 5-46
  12375. SoundComponentSetOutput function5-41 to 5-42
  12376. SoundComponentSetSource function5-38 to 5-39
  12377. SoundComponentStartSource function5-46 to 5-47
  12378. SoundComponentStopSource function5-47 to 5-48
  12379. Sound control panels
  12380. effect on loudness of sounds2-27
  12381. extensions to1-10
  12382. and SysBeep procedure1-24, 1-35, 2-121
  12383. sound data. See sampled-sound data, sounds, square-wave data, wave-table data
  12384. SoundDataChunk data type2-87, 2-117
  12385. Sound Data Chunks2-82, 2-87, 2-117 to 2-118
  12386. sound double buffer header records2-69, 2-111 to 2-112
  12387. sound double buffer records2-69, 2-112 to 2-113
  12388. Sound Driver2-7
  12389. sound files. See also AIFF files, AIFF-C files
  12390. advantages over sound resources1-18
  12391. asynchronous playing2-52
  12392. and Finder sound files1-19
  12393. getting information about2-62 to 2-66
  12394. introduced1-18 to 1-20
  12395. pausing play2-53
  12396. playing1-26 to 1-27, 1-36 to 1-38, 2-123 to 2-125
  12397. playing several simultaneously1-20
  12398. reading2-87 to 2-89
  12399. recording1-31, 1-40 to 1-41, 3-30
  12400. setting up3-46 to 3-48
  12401. stopping play2-53
  12402. structure of2-81 to 2-89
  12403. translating between operating systems1-18
  12404. writing2-87 to 2-89
  12405. SoundHeader data type2-104
  12406. sound header records2-104 to 2-105
  12407. sound headers
  12408. accessing fields of2-61
  12409. compressed2-108 to 2-111
  12410. defined2-10
  12411. extended2-106 to 2-108
  12412. formats of3-45
  12413. getting pointers to2-57 to 2-61, 2-138 to 2-139
  12414. setting up3-4, 3-44 to 3-46
  12415. standard2-104 to 2-105
  12416. types of2-10, 2-62
  12417. Sound In control panel1-15 to 1-16
  12418. selecting sound input device from list3-49
  12419. SoundInfoList data type5-31 to 5-32
  12420. sound information lists5-31 to 5-32
  12421. sound input completion routines
  12422. defined3-9, 3-54 to 3-55
  12423. setting3-6, 3-27
  12424. sound input device drivers3-13 to 3-17
  12425. and continuous recording3-17
  12426. getting information about3-4, 3-41 to 3-44
  12427. installing and initializing3-13
  12428. and Memory Manager errors3-15
  12429. registering with Sound Input Manager3-13, 3-48, 3-50
  12430. routines for3-5
  12431. and stereo recording3-16
  12432. storage for3-13
  12433. types of requests drivers can handle3-13
  12434. sound input device information selectors
  12435. introduced3-5
  12436. list of3-18 to 3-25
  12437. required selectors3-15
  12438. reserved by Apple3-15
  12439. responding to requests for more than 18 bytes of data3-13
  12440. sound input devices
  12441. changing settings of3-10 to 3-12, 3-41 to 3-44
  12442. closing3-4, 3-32 to 3-33
  12443. connection state3-22
  12444. current1-16
  12445. displaying Options dialog box for3-23
  12446. generating list of3-49 to 3-50
  12447. getting information about3-4, 3-10 to 3-12, 3-18 to 3-25
  12448. opening3-4, 3-9, 3-31 to 3-32
  12449. recording directly from3-6 to 3-9, 3-33 to 3-38
  12450. registering3-48 to 3-51
  12451. sound input interrupt routines
  12452. defined3-10, 3-55 to 3-56
  12453. executing from sound input device driver3-16
  12454. setting3-6, 3-27
  12455. Sound Input Manager3-3 to 3-67
  12456. application-defined routines3-53 to 3-56
  12457. completion routines3-9, 3-54 to 3-55
  12458. constants in3-17 to 3-25
  12459. data structures in3-26 to 3-27
  12460. interrupt routines3-10, 3-55 to 3-56
  12461. introduced1-5, 1-15 to 1-17
  12462. recording features3-5
  12463. routines in3-27 to 3-53
  12464. testing for availability3-13, 3-17 to 3-18
  12465. testing for version3-53
  12466. sound input parameter blocks
  12467. accessing from a sound input device driver3-15
  12468. format of3-6, 3-26 to 3-27
  12469. setting up3-7 to 3-8
  12470. uses for3-26
  12471. Sound Manager2-5 to 2-189
  12472. application-defined routines2-151 to 2-154
  12473. and audio components6-3 to 6-5
  12474. callback procedures2-46 to 2-51, 2-152 to 2-153
  12475. completion routines2-47, 2-151 to 2-152
  12476. constants in2-89 to 2-99
  12477. data structures in2-99 to 2-119
  12478. doubleback procedures2-153 to 2-154
  12479. enhanced1-14 to 1-15
  12480. features new in version 3.01-14
  12481. improving efficiency2-61
  12482. introduced1-5, 1-9 to 1-15
  12483. obtaining information2-32 to 2-41
  12484. relation to audio hardware1-11
  12485. routines in2-119 to 2-151
  12486. and sound components5-4 to 5-8
  12487. sound component utility routines5-33 to 5-36
  12488. testing for features2-33 to 2-34, 2-35 to 2-37, 2-90 to 2-91
  12489. testing for version2-34 to 2-35, 2-133
  12490. turning off sound output2-27
  12491. Sound Manager status records2-39, 2-102
  12492. Sound Out control panel1-10
  12493. sound output device components5-5, 5-46 to 5-49
  12494. sound output devices
  12495. initializing5-17 to 5-18, 5-37 to 5-38
  12496. sound output rate2-16
  12497. SoundParamBlock data type5-30 to 5-31
  12498. sound parameter blocks5-30 to 5-31
  12499. sound queues
  12500. bypassing1-12, 2-11
  12501. specifying size2-21
  12502. sound recording dialog box
  12503. customizing behavior of1-29, 3-4
  12504. filtering events in1-29
  12505. introduced1-17
  12506. recording sounds with1-28 to 1-31
  12507. sound-recording equipment
  12508. checking for1-27 to 1-28
  12509. types supported1-27
  12510. sound resource headers2-155 to 2-156
  12511. sound resources. See also 'snd ' resource type
  12512. alternatives to2-9
  12513. containing sampled-sound data2-77
  12514. creating manually2-155
  12515. format of2-74 to 2-80, 2-154 to 2-155
  12516. freeing memory after playing2-25
  12517. getting information about2-57 to 2-61
  12518. introduced1-17 to 1-18
  12519. number of commands used in2-21
  12520. playing
  12521. described1-25 to 1-26, 1-35 to 1-38, 2-121 to 2-123, 2-123 to 2-125
  12522. example of use2-57
  12523. ignoring parts of2-61
  12524. large resources with a small buffer2-61
  12525. recording1-28 to 1-30, 1-39 to 1-40, 3-28 to 3-29
  12526. reserved IDs2-75, 2-154
  12527. sounds. See also sampled sounds
  12528. amplitude2-8, 2-27 to 2-28
  12529. changing output channel for2-24
  12530. computed2-9
  12531. determinants of loudness2-27
  12532. digitally recorded2-9
  12533. duration2-7
  12534. frequency2-7
  12535. installing into System file1-19
  12536. looping2-45 to 2-46
  12537. manipulating while playing2-25 to 2-28
  12538. mixing5-6 to 5-7
  12539. pitch2-7
  12540. recording. See recording sounds
  12541. sample rate. See sample rates
  12542. synchronizing with other actions2-51
  12543. timbre2-8
  12544. volume2-8
  12545. sound sources
  12546. adding5-42 to 5-43
  12547. pausing5-48
  12548. removing5-43 to 5-44
  12549. starting5-46 to 5-47
  12550. stopping5-47 to 5-48
  12551. sound storage formats2-74 to 2-89
  12552. source components5-5, 5-38 to 5-40
  12553. source IDs5-7
  12554. sources. See sound sources
  12555. SPBBytesToMilliSeconds function3-52
  12556. SPBCloseDevice function3-4, 3-32 to 3-33
  12557. SPB data type3-6, 3-26
  12558. SPBGetDeviceInfo function
  12559. described3-42
  12560. example of use3-8
  12561. information selectors, list of3-20 to 3-25
  12562. introduced3-5
  12563. using in interrupt routines3-10
  12564. SPBGetIndexedDevice function3-31, 3-49 to 3-50
  12565. SPBGetRecordingStatus function3-40 to 3-41
  12566. SPBMilliSecondsToBytes function3-51 to 3-52
  12567. SPBOpenDevice function3-31 to 3-32
  12568. example of use3-8
  12569. introduced3-4
  12570. and sound input parameter blocks3-26
  12571. SPBPauseRecording function3-4, 3-38
  12572. SPBRecord function3-33 to 3-35
  12573. example of use3-8
  12574. introduced3-4
  12575. and sound input completion routines3-9
  12576. SPBRecordToFile function3-4, 3-35 to 3-38
  12577. SPBResumeRecording function3-4, 3-39
  12578. SPBSetDeviceInfo function3-5, 3-10, 3-43 to 3-44
  12579. SPBSignInDevice function3-5, 3-48 to 3-49
  12580. SPBSignOutDevice function3-5, 3-50 to 3-51
  12581. SPBStopRecording function
  12582. described3-39 to 3-40
  12583. introduced3-4
  12584. and sound input completion routines3-9, 3-27
  12585. and sound input parameter blocks3-27
  12586. SPBVersion function3-53
  12587. SpeakBuffer function4-57 to 4-59
  12588. SpeakString function1-33 to 1-34, 1-42 to 1-43, 4-55 to 4-56
  12589. SpeakText function4-56 to 4-57
  12590. speech
  12591. bilingual1-22, 4-9
  12592. continuous4-19, 4-51, 4-58
  12593. minimizing latency period of4-52, 4-59
  12594. multilingual1-22, 4-9
  12595. pausing4-18 to 4-19, 4-61 to 4-62
  12596. phonemic representation of4-32 to 4-34, 4-37
  12597. resuming4-19, 4-62 to 4-63
  12598. starting4-18 to 4-19, 4-56 to 4-59
  12599. stopping1-33 to 1-34, 1-42, 4-18 to 4-19, 4-56, 4-59 to 4-61
  12600. synchronous generation1-33
  12601. tonal qualities of1-21, 4-5
  12602. speech amplitude. See speech volume
  12603. speech attributes
  12604. changing the rate and pitch4-16 to 4-17, 4-74 to 4-75, 4-76
  12605. defined4-6 to 4-9
  12606. SpeechBusy function1-43, 4-72
  12607. SpeechBusySystemWide function4-72 to 4-73
  12608. speech channel control flags
  12609. changing during speech4-83
  12610. described4-51 to 4-52, 4-58 to 4-59
  12611. speech channels
  12612. changing settings of4-78 to 4-79
  12613. control flags. See speech channel control flags
  12614. creating4-13 to 4-14, 4-69 to 4-70
  12615. defined1-22, 4-9
  12616. disposing of4-13 to 4-14, 4-70 to 4-71
  12617. getting information about4-77 to 4-78
  12618. limitations on1-22, 4-10
  12619. multiple1-22, 4-10
  12620. number synthesizing speech4-72
  12621. preventing interruption of speech4-51, 4-58
  12622. reference constant values4-20
  12623. setting up callback procedures4-21
  12624. speaking text with4-13 to 4-14
  12625. and suspend events4-70
  12626. speech commands. See embedded speech commands
  12627. speech components1-20, 4-5
  12628. speech-done callback procedures4-19, 4-84 to 4-85
  12629. SpeechErrorInfo data type4-49
  12630. speech error information records4-49 to 4-50
  12631. speech extension data records4-53 to 4-54
  12632. speech generation process1-20 to 1-22, 4-4
  12633. speech information selectors4-39 to 4-45
  12634. speech input mode4-33
  12635. Speech Manager4-3 to 4-110
  12636. application-defined routines4-82 to 4-89
  12637. callback procedures4-10, 4-19 to 4-23
  12638. common uses of4-3
  12639. and Component Manager1-20, 4-5
  12640. constants in4-39 to 4-45
  12641. data structures in4-45 to 4-54
  12642. future improvements in1-21, 4-5
  12643. introduced1-5, 1-20 to 1-22
  12644. memory requirements of1-22, 4-32
  12645. position in speech generation process1-20, 4-5
  12646. resources4-89 to 4-93
  12647. result code of routines4-55
  12648. routines in4-54 to 4-82
  12649. and Sound Manager4-3
  12650. testing for availability1-31 to 1-32, 4-12 to 4-13
  12651. testing for version4-71 to 4-72
  12652. and voices4-5 to 4-6, 4-14 to 4-16, 4-63 to 4-68
  12653. SpeechManagerVersion function4-71 to 4-72
  12654. speech modulation. See pitch modulation
  12655. speech pitch
  12656. causing rise or fall in4-35
  12657. changing4-16 to 4-17, 4-76
  12658. defined4-7
  12659. distinguished from frequency4-8
  12660. getting4-75 to 4-76
  12661. and Hertz values4-7
  12662. range used by human voices4-7
  12663. speech rate
  12664. changing4-16 to 4-17, 4-74 to 4-75
  12665. defined4-6, 4-43
  12666. getting4-73 to 4-74
  12667. speech rate embedded speech command4-28
  12668. SpeechStatusInfo data type4-49
  12669. speech status information records4-48 to 4-49
  12670. speech synthesizer resources4-89
  12671. speech synthesizers
  12672. defined1-20, 4-4
  12673. getting information about phonemes supported4-34
  12674. internal dictionaries4-91
  12675. memory requirements of4-10
  12676. minimizing latency period of4-52, 4-59
  12677. SpeechVersionInfo data type4-50
  12678. speech version information records4-50 to 4-52
  12679. speech volume4-45
  12680. defined4-9
  12681. speech volume embedded speech command4-29
  12682. SpeechXtndData data type4-53
  12683. square-wave data2-7 to 2-8
  12684. standard sound headers2-104 to 2-105
  12685. StateBlock data type2-119
  12686. state blocks2-119
  12687. state buffers, used by MACE routines2-67
  12688. Status calls3-5, 3-13 to 3-15
  12689. stereo sounds
  12690. defined2-106
  12691. expanding2-15
  12692. recording3-16
  12693. storage format of2-10
  12694. stopping speech4-59 to 4-61
  12695. StopSpeechAt function4-60 to 4-61
  12696. StopSpeech function4-59 to 4-60
  12697. strings, converting into speech. See speech generation
  12698. 'STR ' resource type5-9, 6-6
  12699. suspend events, disposing of speech channels in response to4-70
  12700. syllable break symbols4-34
  12701. syncCmd command2-30 to 2-31, 2-94
  12702. sync embedded speech command selector4-29
  12703. synchronization callback procedures4-19 to 4-20, 4-85 to 4-86
  12704. synchronization embedded speech command4-29
  12705. synchronization messages4-20
  12706. synchronizing sound channels2-30 to 2-31, 2-95
  12707. synchronizing sounds with other actions2-51
  12708. synthesizers. See speech synthesizers
  12709. synthesizer-specific embedded speech command4-29
  12710. SysBeep procedure
  12711. described1-35, 2-120 to 2-121
  12712. example use of1-24
  12713. using as notification1-25
  12714. system alert sounds
  12715. determining status of2-40 to 2-41, 2-137
  12716. disabling2-40 to 2-41
  12717. editing list of1-16
  12718. enabling2-40 to 2-41
  12719. installing new sound1-19
  12720. producing1-24 to 1-25, 1-35, 2-120 to 2-121
  12721. setting status of2-137 to 2-138
  12722. T
  12723.  
  12724. text
  12725. conversion into phonemes4-32 to 4-33, 4-79 to 4-80
  12726. specifying allophones in4-33
  12727. text-done callback procedures4-19, 4-82 to 4-84
  12728. text processing modes4-42
  12729. TextToPhonemes function4-32, 4-79 to 4-80
  12730. text-to-speech. See Speech Manager
  12731. 'thng' resource type5-8 to 5-11, 6-5 to 6-7
  12732. ticks, used to time system alert sounds1-25
  12733. timbre2-8, 2-28, 2-96
  12734. timbreCmd command2-28, 2-96
  12735. Time Manager, and synchronizing sounds2-31
  12736. totalLoadCmd command2-95
  12737. 'ttsd' resource type4-91
  12738. two’s complement encoding2-11
  12739. U
  12740.  
  12741. uncompressed sound data. See decompressed sound data, noncompressed sound data
  12742. unit table, installing sound input device driver into3-13
  12743. unsigned fixed-point numbers, multiplying and dividing2-149
  12744. UnsignedFixMulDiv function2-149
  12745. UseDictionary function4-38, 4-81 to 4-82
  12746. user interface guidelines, for sound1-23 to 1-24
  12747. utility components5-6
  12748. V
  12749.  
  12750. vers embedded speech command selector4-29
  12751. versionCmd command2-95
  12752. version embedded speech command4-29
  12753. version records2-118
  12754. version resources2-35, 2-118
  12755. 'vers' resource type2-35, 2-118
  12756. VoiceDescription data type4-47
  12757. voice description records4-16, 4-47 to 4-48
  12758. VoiceFileInfo data type4-48
  12759. voice file information records4-48
  12760. voice resources4-89
  12761. voices
  12762. characteristics of4-6 to 4-9
  12763. counting4-14, 4-64 to 4-65
  12764. defined4-5 to 4-6
  12765. getting a description of4-14, 4-66 to 4-67
  12766. identifying4-14, 4-65 to 4-66
  12767. installing into sound channels2-10, 2-43 to 2-45
  12768. synthesized1-22
  12769. updating information about4-66
  12770. VoiceSpec data type4-46
  12771. voice specification records4-46 to 4-47, 4-64
  12772. volm embedded speech command selector4-29
  12773. volume. See also amplitude, speech volume
  12774. defined2-8
  12775. volumeCmd command2-31, 2-96
  12776. volume levels, controlling2-31 to 2-32, 2-96 to 2-97, 2-139 to 2-142
  12777. Volumes control panel6-4 to 6-5
  12778. VOX recording3-5, 3-25
  12779. VOX stopping3-5, 3-25
  12780. W
  12781.  
  12782. waitCmd command
  12783. described2-94
  12784. example of use2-29
  12785. waveTableCmd command2-44, 2-97
  12786. wave-table data2-8
  12787. wave tables2-8, 2-44
  12788. word callback procedures
  12789. described4-88 to 4-89
  12790. example of4-22
  12791. word prominence symbols4-34
  12792. X, Y, Z
  12793.  
  12794. xtnd embedded speech command selector4-29
  12795. This Apple manual was written, edited, and composed on a desktop publishing system using Apple Macintosh computers and FrameMaker software. Proof pages were created on an Apple LaserWriter IINTX printer. Final page negatives were output directly from text files on an Optrotech SPrint 220 imagesetter. Line art was created using Adobe Illustrator™ and Adobe Photoshop™. PostScript™, the page-description language for the LaserWriter, was developed by Adobe Systems Incorporated.
  12796. Text type is Palatino® and display type is Helvetica®. Bullets are ITC Zapf Dingbats®. Some elements, such as program listings, are set in Apple Courier.
  12797. LEAD WRITER
  12798. Tim Monroe
  12799. WRITERS
  12800. Tim Monroe, Michael Abramowicz, Lori E. Kaplan
  12801. DEVELOPMENTAL EDITORS
  12802. Sanborn Hodgkins, Wendy Krafft, Antonio Padial, Laurel Rezeau, Beverly Zegarski
  12803. ILLUSTRATORS
  12804. Shawn Morningstar, Barbara Carey
  12805. ART DIRECTOR
  12806. Bruce Lee
  12807. PRODUCTION EDITOR
  12808. Gerri Gray
  12809. PROJECT MANAGER
  12810. Patricia Eastman
  12811. COVER DESIGNER
  12812. Barbara Smyth
  12813. Special thanks to Mark Cecys, Kip Olson, Jim Reekes, and Tim Schaaff.
  12814. Acknowledgments to Bob Aron, Ray Chiang, Ron Dumont, Sharon Everson, Eric “Braz” Ford, Jim Nitchals, Guillermo Ortiz, Kim Silverman, George Towner, Randy Zeitman, and the entire Inside Macintosh team.
  12815. &@ˇ ˇˇˇˇ@
  12816. ˇ·ˇ‚7^
  12817. 4í∫◊, Palatino
  12818. .°dONLNdˇˇ(ô∫    Addison-WÑ@°dONLNdˇˇ)4esley Publishing Company
  12819.     °dONLNdˇˇ(´∫Reading, MassachusettsÀ†°dONLNdˇˇ)hMenlo Park, California쇰dONLNdˇˇ)dNew ˆ∞°dONLNdˇˇ)Y#°dONLNdˇˇ)ork°dONLNdˇˇ(∑∫Don Mills, Ontarioc °dONLNdˇˇ)TW膰dONLNdˇˇ)okingham, England@°dONLNdˇˇ)XAmsterܰdONLNdˇˇ)damwp°dONLNdˇˇ)Bonn°dONLNdˇˇ(√∫SydneyH °dONLNdˇˇ)'Singapor°dONLNdˇˇ)$ee∞°dONLNdˇˇ)
  12820. T°dONLNdˇˇ)okyoÏP°dONLNdˇˇ)Madrid–°dONLNdˇˇ)(San Juan°dONLNdˇˇ(œ∫Parisl¿°dONLNdˇˇ)Seoulk`°dONLNdˇˇ)MilanËİdONLNdˇˇ)  Mexico City °dONLNdˇˇ):T»Ä°dONLNdˇˇ)aipei
  12821. (0∫4Ÿ∫˘
  12822. {∂èÕ4zµ{∂ê{∂èÕ08x|˛˛ˇˇ?ˇ¯?ÔÔ«‡á‡É¿¿Äê{∂èÕ08||«‡É¿¿ÄÄ
  12823. ˇ·ˇ‚7^
  12824. 3 ðdONLNdí∫´‘*t
  12825. INSIDE MACINT∫ °dONLNd
  12826. í‘´(§‘OSH
  12827. ˙H 4˚H  H
  12828. ˇ·ˇ‚7^
  12829. ˇˇ≥>ˇ◊°dONLNd
  12830. H.ú(&HSoundˇ,†@ˇ ˇˇˇˇ@
  12831. ˇ·ˇ‚7^ X*XÙ
  12832. 4⁄*˙¯4^*.∫, Palatino
  12833. .°dONLNdZ*f1+*c
  12834. °dONLNd\6er) Apple Computer>İdONLNd\reÇ)<, Inc.°dONLNdg*pC(n*© 1994 .İdONLNdgDpÄ)Apple Computer̰dONLNd,gpè);, Inc.°dONLNd3p*yP(w* All rights r˝Ä°dONLNd?pPyo)&    eserved. °dONLNdI{*Ñ•(Ç*#No part of this publication may be °dONLNdlÑ*ç-*    rÑİdONLNdmÑ-ç8)epr-°dONLNdpÑ9çd) oduced, storËİdONLNd|ÑdçÄ)+    ed in a r°°dONLNdÖÑÅçù)    etrieval °dONLNdéç*ñ≤(î*'system, or transmitted, in any form or °dONLNdµñ*üû*     by any means, mechanical, electréİdONLNd’ñûü∞)tonic, °dONLNd€ü*®b(¶*photocopying, rÔİdONLNdÍüb®p)8ecor¥°dONLNdÓüq®µ)ding, or otherwise, °dONLNd®*±™(Ø*$without prior written permission of °dONLNd&±*∫f*    Apple Computer>İdONLNd4±f∫´)<, Inc. Printed in the °dONLNdJ∫*√d(¡*United States of iİdONLNd[∫d√Ñ):America.°dONLNdd≈*Œf(Ã*No licenses, exprúİdONLNdu≈fŒ¢)<ess or implied, arX°dONLNdá≈£Œ®)=e °dONLNdâŒ*◊](’*granted with r`İdONLNdóŒ]◊£)3espect to any of the °dONLNd¨◊*‡•(fi*#technology described in this book. °dONLNdœ‡*ÈE*    Apple rÑİdONLNd÷‡EÈó)etains all intellectual pr °dONLNd‡òȱ)Soperty °dONLNd˜È*ÚØ(*&rights associated with the technology °dONLNdÚ*˚®*    %described in this book. This book is °dONLNdB˚*ì*    intended to assist application °dONLNda*
  12835. π*    (developers to develop applications only °dONLNdâ
  12836. *6*    for eİdONLNdç
  12837. 6ú) Apple Macintosh computers.°dONLNd®*!G(*Every ef≥İdONLNd∞G!©)fort has been made to ensurΔ°dONLNdÀ©!Æ)be °dONLNdÕ!**Ø((*'that the information in this manual is °dONLNdÙ**3K*    
  12838. accurate. ªÄ°dONLNd˛*K3{)!Apple is not r°dONLNd *|3Ø)1esponsible for °dONLNd3*<w(:*printing or clerical errİdONLNd33x<Ñ)Nors.°dONLNd8@*If(G*Apple Computer>İdONLNdF@fIv)<, Inc.°dONLNdMI*R^(P*20525 Mariani >İdONLNd[I^Rd)4AªÄ°dONLNd\IcRx)venue°dONLNdbR*[^(Y*
  12839. Cupertino, CA6İdONLNdoR^[t)4 95014°dONLNdv[*dW(b* 408-996-1010°dONLNdÉh*qQ*
  12840. Apple, the MİdONLNdéhQq|)' Apple logo, Ö°dONLNdöh|qó)+APDA, °dONLNd†q*zM(x*HyperCarİdONLNd®qNzr)$    d, LaserW©°dONLNd±qqzÄ)#riter(İdONLNd∂qÄz≠)
  12841. , Macintosh, °dONLNd√z*ÉÑ(Å*Macintosh Quadra, MPWs°dONLNdÿzÑÉó)Z, and °dONLNdfiÉ*å\(ä* PowerBook arsİdONLNdÍÉ\åï)2e trademarks of í°dONLNd˙Éïå≠)9Apple °dONLNdå*ïN(ì*Computer>İdONLNdåNïf)$    , Inc., r*°dONLNdåfï})egisterüİdONLNdå}ï∏)ed in the United °dONLNd)ï*ûá(ú*States and other countries.°dONLNdE†*©\*
  12842. AppleDesign, 
  12843. İdONLNdR†]©y)3AudioV°dONLNdX†y©•)
  12844. ision, FinderœÄ°dONLNde†§©®)+, °dONLNdg©*≤E(∞*MacinT≈°dONLNdm©D≤|)alk, QuickDrawG°dONLNd{©|≤©)8 , and QuickTπİdONLNdá©©≤∏)-ime °dONLNdã≤*ª1(π*arÑİdONLNdç≤1ªj)e trademarks of £°dONLNdù≤jª¶)9Apple ComputeraİdONLNd´≤¶ª∂)<, Inc.°dONLNd≤Ω*Δg(ƒ*Adobe IllustratorİdONLNd√ΩgΔk)=, “°dONLNd≈ΩjΔ≠)Adobe Photoshop, °dONLNd÷Δ*œf(Õ*and PostScript arÍİdONLNdÁΔfœü)<e trademarks of     °dONLNd˜Δ†œπ):Adobe °dONLNd˝œ*ÿÆ(÷*#Systems Incorporated, which may be °dONLNd ÿ*·-*    rÑİdONLNd!ÿ-·D)egister˙°dONLNd(ÿD·ü)ed in certain jurisdictions.°dONLNdE„*ÏB(Í*Classic
  12845. )°dONLNdL‚CÈG(ÁC®
  12846. §Ä°dONLNdM„GÏY+ is a ra°dONLNdT„ZÏq)egister÷İdONLNd[„qÏ¢)
  12847. ed trademark °dONLNdhÏ*ıQ(Û* licensed to ¸Ä°dONLNdtÏQıç)'Apple Computerª°dONLNdÇÏçıù)<, Inc.°dONLNdâ˜*j(˛*FrameMaker is a røÄ°dONLNdö˜jÅ)@egister5°dONLNd°˜Ç≥)
  12848. ed trademark °dONLNdÆ*    P(*
  12849. of Frame T4°dONLNd∏P    §)&echnology Corporation.°dONLNdœ *É(*Helvetica and Palatino ar÷İdONLNdË Éã)Ye r∞°dONLNdÎ å£)    egister%İdONLNdÚ §Æ)ed °dONLNdı*¢(*trademarks of Linotype Company&°dONLNd¢§)x.4^….Y°dONLNd\…e?(c…#Internet is a trademark of Digital °dONLNd8e…n*    Equipment Corporation.°dONLNdOp…y* ITC Zapf Dingbats is a r]İdONLNdgpy5)Uegister”°dONLNdnp5y?)ed °dONLNdqy…Ç-(Ä…trademark of International TΔ°dONLNdçy-ÇJ)dypeface °dONLNdïÇ…ãˆ(â… Corporation.°dONLNd¢ç…ñ.* NuBus™ is a trademark of T¸°dONLNdºç-ñ>)dexas °dONLNd¡ñ…üŸ(ù…InstrÛ°dONLNdΔñŸüı)uments.°dONLNdŒ°…™Ÿ(®…Optr9İdONLNd“°⁄™O)!otech is a trademark of Orbotech °dONLNdÛ™…≥ˆ(±… Corporation.°dONLNdµ…æ6* Sony™ is a trademark of Sony °dONLNdæ…«˚*    Corporation, rİdONLNd+渫)3egistery°dONLNd2æ«S)ed in the U.S. and °dONLNdE«…–(Œ…other countries.°dONLNdV‘…›X*
  12850. 'Simultaneously published in the United °dONLNd}›…Ê *    States and Canada.
  12851. °dONLNdêÙ…¸Ò*    LIMITED W°dONLNdôÙÒ¸=)(ARRANTY ON MEDIAöp°dONLNd©Ù=¸Q)L AND °dONLNdÆ˝…ˇ(… REPLACEMENT°dONLNd∫
  12852. …÷*
  12853. ALL_0°dONLNdΩ
  12854. ◊)
  12855.  IMPLIED WYê°dONLNd«
  12856. M))ARRANTIES ON THIS °dONLNdŸ…<(…MANUAL, INCLUDING IMPLIED °dONLNdÛ…$–*    Wfl°dONLNdÙœ$2)ARRANTIES OF MERCHANTd°dONLNd    2$P)cABILITY °dONLNd%…-(+…AND FITNESS FOR AÊ∞°dONLNd"%-)H Ph¿°dONLNd$%-!)ARÜP°dONLNd&%!-C)
  12857. TICULAR °dONLNd..…6?(4…PURPOSE, ARE LIMITED IN DURA¶ °dONLNdJ.?6S)vTION °dONLNdO7…? (=…TO NINETY (90) DAiİdONLNd`7 ?I)BYS FROM THE DAÀ†°dONLNdn7H?R)=TE °dONLNdq@…H
  12858. (F…OF THE ORIGINAL∞°dONLNdÄ@ H)B RET30°dONLNdÑ@H&)AILÖ °dONLNdá@&HQ)
  12859.  PURCHASE °dONLNdëI…Q (O…OF THIS PRODUCTæ`°dONLNd†I Q )B.°dONLNd¢V…^B(\…$Even though Apple has reviewed this °dONLNdΔ_…g-*    manual, APPLE MAKES NO Wa@°dONLNdfi_-gR)dARRANTY °dONLNdÊh…pˇ(n… OR REPRESENT{¿°dONLNdÚhˇp)6AI °dONLNdÛhpW)TION, EITHER EXPRESS °dONLNd    q…yO(w…!OR IMPLIED, WITH RESPECT TO THIS °dONLNd    )z…Ç*    MANUAL, ITS QUALITYf∞°dONLNd    <zÇH)S
  12860. , ACCURACYõİdONLNd    FzHÇK),, °dONLNd    HÉ…ãÙ(â…MERCHANT°dONLNd    PÉÙã)+ABILITY≠p°dONLNd    WÉãU), OR FITNESS FOR A[†°dONLNd    iÉVãW)F °dONLNd    jå…îÕ(í…PB°dONLNd    kåÕî◊)AR_†°dONLNd    må◊î/)
  12861. TICULAR PURPOSE. AS AÑê°dONLNd    Çå/îH)X RESUL‡°dONLNd    àåHîL)T†°dONLNd    âåLîO), °dONLNd    ãï…ù˝(õ… THIS MANUAL°dONLNd    ñï˛ùN)5 IS SOLD “AS IS,” AND °dONLNd    ¨û…¶X(§…!YOU, THE PURCHASER, ARE ASSUMING °dONLNd    Õß…ØQ*    "THE ENTIRE RISK AS TO ITS QUALITY °dONLNd    Ô∞…∏*     AND ACCURACY0°dONLNd    ˚∞∏)<.°dONLNd    ˝Ω…≈
  12862. (√…IN NO EVENT WILLùp°dONLNd
  12863.  
  12864. Ω
  12865. ≈M)D APPLE BE LIABLE °dONLNd
  12866. Δ…Œı(Ã…
  12867. FOR DIRECTˇ@°dONLNd
  12868. (ΔÙŒ)+
  12869. , INDIRECT °dONLNd
  12870. 2ΔŒA)( , SPECIAL, °dONLNd
  12871. =œ…◊Ì(’…INCIDENTÃİdONLNd
  12872. EœÌ◊F)$AL, OR CONSEQUENTIALK°dONLNd
  12873. YœG◊H)Z °dONLNd
  12874. Zÿ…‡(fi…
  12875. DAMAGES RESUL)–°dONLNd
  12876. gÿ‡F)?TING FROM ANY °dONLNd
  12877. u·…ÈD(Á…DEFECT OR INACCURACY IN THIS °dONLNd
  12878. íÍ…ÚX*    +MANUAL, even if advised of the possibility °dONLNd
  12879. ΩÛ…˚ˇ*    of such damages.°dONLNd
  12880. Œ…‡*
  12881. THE We†°dONLNd
  12882. ”‡O)ARRANTY AND REMEDIES SET °dONLNd
  12883. Ï    …◊(…FOR°dONLNd
  12884. Ô    ◊V)TH ABOVE ARE EXCLUSIVE AND IN °dONLNd
  12885. …Ù(… LIEU OF ALLQ°dONLNd ı,),
  12886.  OTHERS, ORAL¸†°dONLNd %,:)7 OR °dONLNd )…#J(!… WRITTEN, EXPRESS OR IMPLIED. No °dONLNd I$…,Ú*     Apple dealerÜ0°dONLNd U$Ú,:)), agent, or employee is 4^h/¯°dONLNd m]he (chauthorized to make any modifi°dONLNd ä] e‡)bcation, °dONLNd ífhn‚(lh'extension, or addition to this warrantyÛ`°dONLNd πf·n‚)y.°dONLNd ªsh{Ì(yh*Some states do not allow the exclusion or °dONLNd Â|hÑÙ*    .limitation of implied warranties or liability °dONLNd ÖhçÙ*    ,for incidental or consequential damages, so °dONLNd ?éhñÓ*    *the above limitation or exclusion may not °dONLNd ióhü‚*    &apply to you. This warranty gives you °dONLNd è†h®|*    specifi¿°dONLNd ñ†}®Û)&c legal rights, and you may also have °dONLNd º©h±Ó(Øh,other rights which vary from state to state.4d*¬∫
  12887. °dONLNd Èb*kn(i*ISBN 0-201-62272-6°dONLNd ¸k*tk*    1 2 3 4 5 6 7 8 9-CR‚İdONLNd
  12888. kkts)AWr°dONLNd
  12889. kstù) -9897969594°dONLNd
  12890. t*}~({*First Printing, May 1994°dONLNd
  12891. 6§*≠≤*0&The paper used in this book meets the °dONLNd
  12892. \≠*∂3*    EP|°dONLNd
  12893. ^≠3∂9)    ADİdONLNd
  12894. _≠9∂U) standar‘°dONLNd
  12895. g≠U∂n)ds for rPİdONLNd
  12896. o≠o∂ê)    ecycled fiïİdONLNd
  12897. y≠ê∂õ)!beri°dONLNd
  12898. |≠õ∂ù) .4d…¬¯°dONLNd
  12899. ~b…kÖ(i…2Library of Congress Cataloging-in-Publication Data°dONLNd
  12900. ±p…yh*)Inside Macintosh. Sound / [Apple ComputeröİdONLNd
  12901. ⁄phy{)ü, Inc.]°dONLNd
  12902. „yÌÇÛ(ÄÌp.O°dONLNd
  12903. Êy¸Ç)cm.°dONLNd
  12904. ÍÇ·ã(â·Includes index.°dONLNd
  12905. ˙ã·î%*    ISBN 0-201-62272-6°dONLNd
  12906. î·ù9*    1. Macintosh (Computer)J°dONLNd%îBùê)a2. Computer sound prìİdONLNd9îêùØ)N    ocessing.äİdONLNdCî∏ùæ)(I. Ò°dONLNdFîæù÷)Apple °dONLNdMù’¶˘(§’Computer>İdONLNdUù˘¶    )$, Inc.°dONLNd\¶’Ø(≠’ QA76.8.M3I53F°dONLNdi¶Ø );1994°dONLNdnØ’∏¸(∂’ 006.5--dc20÷°dONLNdzØ‘∏Ú)ˇ94-16209M°dONLNdÉ∏‚¡Ô+    CIPˇJ@ˇ ˇˇˇˇ@
  12907. ˇ·ˇ‚7^
  12908. 4⁄∫˙, Palatino
  12909. .Ñ`(‡ iii4^H¿
  12910. ^Hö4^Hö
  12911. °dONLNd^∫w(p∫Contents
  12912. ˇ·ˇ‚7^
  12913. °dONLNd    ò∫§“*1FigurR¿°dONLNdò“§Ê)es, Tè °dONLNdò§6)ables, and Listings|@°dONLNd(òK§S)fxi
  12914. ¬H…4√H… ƒHƒ
  12915. ˇ·ˇ‚7^,     Helvetica
  12916. °dONLNd+∂H¡m(æHPreface
  12917. °dONLNd3≥∫¬‚)rAbout ∑@°dONLNd9≥‚¬ )(    This Book
  12918. Û@°dONLNdDµ4¡>)Rxv°dONLNdH…∫’ı(“∫
  12919. Format of a T¿°dONLNdU…ı’6);ypical ChapterM °dONLNde…J’W)Uxvi°dONLNdi÷∫‚E(fl∫Conventions Used in This BookİdONLNdà÷Z‚g)†xvi°dONLNdå„ƒÔ˛(σ
  12920. Special Fonts°‡°dONLNdõ„Ô)Nxvi°dONLNdüƒ¸ (˘ƒT∫¿°dONLNd†…¸)
  12921. ypes of Notes)`°dONLNdØ¸*)Qxvii°dONLNd¥˝ƒ    V(ƒAssembly-Language Information?İdONLNd”˝k    {)ßxvii°dONLNdÿ
  12922. ∫(∫Development EnvirH‡°dONLNdÈ
  12923. 2)WonmentA °dONLNdÒ
  12924. GZ)6xviii°dONLNd˜∫#fi( ∫For Morß°dONLNd˛fi#)$
  12925. e Information" °dONLNd
  12926. /#<)Qxix
  12927. SHZ4THZ UHU
  12928. ˇ·ˇ‚7^
  12929. °dONLNdGHRx(OH    Chapter 1
  12930. °dONLNdD∫S≠)r&Introduction to Sound on the Macintosh
  12931. ‡°dONLNdCF¬Rœ(O¬1-1°dONLNdHZ∫fh(c∫"About Sound on Macintosh Computersâ °dONLNdlZ|fâ)¬1-4°dONLNdpgƒs(pƒSound Capabilities4¿°dONLNdÑg,s9)h1-4°dONLNdàtƒÄÌ(}ƒSound Prx °dONLNdêtÌÄ))oductionÚ`°dONLNdöt(Ä5);1-9°dONLNdûŃç¸(äƒ Sound RecorÀ‡°dONLNd©Ÿç)8ding0İdONLNdØÅ%ç7))1-15°dONLNd¥éƒö(óƒ Sound Resourü¿°dONLNd¿éö)>ces†°dONLNd≈é$ö6)"1-17°dONLNd õƒߘ(§ƒ Sound Files°dONLNd◊õ ß)H1-18°dONLNd‹®ƒ¥(±ƒSpeech GenerationÄ¿°dONLNdÔ®+¥=)g1-20°dONLNdÙµƒ¡C(æƒThe User Interface for Sound°dONLNdµX¡j)î1-23°dONLNd¬∫Œf(À∫"Using Sound on Macintosh Computers»`°dONLNd;¬zŒå)¿1-24°dONLNd@œƒ€Õ(ÿƒPrN†°dONLNdBœŒ€)
  12932. oducing an  °dONLNdMœ€7)4 Alert Sound͇°dONLNdZœK€])I1-24°dONLNd_‹ƒË.(ƒPlaying a Sound Resouri¿°dONLNdu‹.Ë7)jce£†°dONLNdy‹KË])1-25°dONLNd~ȃı!(ÚƒPlaying a Sound File °dONLNdïÈ6ıH)r1-26°dONLNdöˆƒ;(ˇƒChecking For Sound-Recorë@°dONLNd≤ˆ;É)wding EquipmentÕ¿°dONLNd¬ˆó©)\1-27°dONLNd«ƒ›( ƒRecor¢`°dONLNdÛ9)ding a Sound Resour&¿°dONLNdfl:C)]ce`†°dONLNd„Wi)1-28°dONLNd˃›(ƒRecor¢`°dONLNdÌ›*)ding a Sound FileZ°dONLNd?Q)b1-31°dONLNdƒ)X(&ƒ Checking For Speech CapabilitiesìİdONLNd'l)~)®1-31°dONLNd,*ƒ6#(3ƒGenerating Speech FrnİdONLNd@*#6V)_ om a Stringu†°dONLNdM*j6|)G1-32°dONLNdR7∫C(@∫ Sound Refer†°dONLNd]7ÒC)7enceÿİdONLNdc7C*)'1-34°dONLNdhDƒPÎ(MƒRoutines≠`°dONLNdrDˇP);1-34°dONLNdwQŒ](ZŒPlaying Sounds∞İdONLNdáQ']9)Y1-34°dONLNdå^ŒjÁ(gŒRecor¢`°dONLNdë^Áj) ding SoundsmİdONLNdû^3jE)L1-38°dONLNd£kŒw_(tŒGenerating and Stopping SpeechÃ@°dONLNd√kswÖ)•1-41°dONLNd»x∫Ñ(Å∫Summary of SoundcİdONLNd⁄x$Ñ6)j1-44°dONLNdflÖƒë
  12933. (éƒPascal Summary‡°dONLNdÔÖ"ë4)^1-44°dONLNdÙíŒû˙(õŒ    ConstantsưdONLNdˇíû )@1-44°dONLNdüŒ´ı(®ŒRoutines≠`°dONLNdü    ´);1-44°dONLNd¨ƒ∏˘(µƒ    C SummaryᆰdONLNd¨
  12934. ∏)I1-45ˇ@ˇ ˇˇˇˇ@
  12935. ˇ·ˇ‚7^
  12936. 4⁄*ˇ¯, Palatino
  12937. .(·*iv4^*¿¯°dONLNd\∞h‹(e∞    ConstantsưdONLNd \h)@1-45°dONLNdi∞u◊(r∞Routines≠`°dONLNdiÎu˝);1-46°dONLNdv¶Ç‡(¶ Result Codesï`°dONLNd-vÙÇ)N1-47
  12938. ≤*π¯4≥*π¯ ¥*¥¯
  12939. ˇ·ˇ‚7^,     Helvetica
  12940. °dONLNd2¶*±Z(Æ*    Chapter 2
  12941. °dONLNd<£ú≤ˇ)r
  12942. Sound Manager
  12943. ‡°dONLNdK•±!)x2-1°dONLNdPπú≈(¬úAbout the Sound Manager&¿°dONLNdiπ&≈3)ä2-6°dONLNdmΔ¶“⁄(œ¶
  12944. Sound Data© °dONLNdyΔÓ“˚)H2-7°dONLNd}”∞fl…(‹∞Squar%°dONLNdÇ” fl‹)e-WWİdONLNdÖ”€fl)ave DataG°dONLNdè”fl#);2-7°dONLNdì‡∞Ï∫(È∞Wï°dONLNdî‡πÏ—)    ave-TéİdONLNdô‡—Ï˙)    able DataG¿°dONLNd§‡Ï)>2-8°dONLNd®Ì∞˘(ˆ∞Sampled-Sound Data‡†°dONLNdºÌ"˘/)r2-9°dONLNd¿˙¶¯(¶Sound Commands °dONLNd–˙
  12945. )g